def find_files(directory, pattern, recursive=True):
    """
    Find files by pattern in directory
    """
    if not os.path.isdir(directory):
        if os.path.exists(directory):
            raise IOError(directory + ' is not directory')
        else:
            raise IOError(directory + " does not exists")
    if recursive:
        for root, _, files in os.walk(directory):
            for basename in files:
                if fnmatch.fnmatch(basename, pattern):
                    filename = os.path.join(root, basename)
                    yield filename
    else:
        root = directory
        for basename in os.listdir(root):
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                if os.path.isfile(filename):
                    yield filename

def
find_files
(
directory
,
pattern
,
recursive
=
True
)
:
if
not
os
.
path
.
isdir
(
directory
)
:
if
os
.
path
.
exists
(
directory
)
:
raise
IOError
(
directory
+
' is not directory'
)
else
:
raise
IOError
(
directory
+
" does not exists"
)
if
recursive
:
for
root
,
_
,
files
in
os
.
walk
(
directory
)
:
for
basename
in
files
:
if
fnmatch
.
fnmatch
(
basename
,
pattern
)
:
filename
=
os
.
path
.
join
(
root
,
basename
)
yield
filename
else
:
root
=
directory
for
basename
in
os
.
listdir
(
root
)
:
if
fnmatch
.
fnmatch
(
basename
,
pattern
)
:
filename
=
os
.
path
.
join
(
root
,
basename
)
if
os
.
path
.
isfile
(
filename
)
:
yield
filename


def In(sigOrVal, iterable):
    """
    Hdl convertible in operator, check if any of items
    in "iterable" equals "sigOrVal"
    """
    res = None
    for i in iterable:
        i = toHVal(i)
        if res is None:
            res = sigOrVal._eq(i)
        else:
            res = res | sigOrVal._eq(i)

    assert res is not None, "Parameter iterable is empty"
    return res

def
In
(
sigOrVal
,
iterable
)
:
res
=
for
i
in
iterable
:
i
=
toHVal
(
i
)
if
res
is
:
res
=
sigOrVal
.
_eq
(
i
)
else
:
res
=
res
|
sigOrVal
.
_eq
(
i
)
assert
res
is
not
,
"Parameter iterable is empty"
return
res

Hdl convertible in operator check if any of items in iterable equals sigOrVal


def StaticForEach(parentUnit, items, bodyFn, name=""):
    """
    Generate for loop for static items

    :param parentUnit: unit where this code should be instantiated
    :param items: items which this "for" itering on
    :param bodyFn: function which fn(item, index) or fn(item)
        returns (statementList, ack).
        It's content is performed in every iteration.
        When ack is high loop will fall to next iteration
    """

    items = list(items)
    itemsCnt = len(items)
    if itemsCnt == 0:
        # if there are no items there is nothing to generate
        return []
    elif itemsCnt == 1:
        # if there is only one item do not generate counter logic generate
        return bodyFn(items[0], 0)
    else:
        # if there is multiple items we have to generate counter logic
        index = parentUnit._reg(name + "for_index",
                                Bits(log2ceil(itemsCnt + 1), signed=False),
                                defVal=0)
        ackSig = parentUnit._sig(name + "for_ack")

        statementLists = []
        for i, (statementList, ack) in [(i, bodyFn(item, i))
                                        for i, item in enumerate(items)]:
            statementLists.append(statementList + [(ackSig(ack)), ])

        If(ackSig,
           If(index._eq(itemsCnt - 1),
              index(0)
              ).Else(
               index(index + 1)
           )
           )

        return Switch(index)\
            .addCases(
            enumerate(statementLists)
        ).Default(
            bodyFn(items[0], 0)[0],
            ackSig(True)
        )

def StaticForEach ( parentUnit , items , bodyFn , name = "" ) : items = list ( items ) itemsCnt = len ( items ) if itemsCnt == 0 : return [ ] elif itemsCnt == 1 : return bodyFn ( items [ 0 ] , 0 ) else : index = parentUnit . _reg ( name + "for_index" , Bits ( log2ceil ( itemsCnt + 1 ) , signed = False ) , defVal = 0 ) ackSig = parentUnit . _sig ( name + "for_ack" ) statementLists = [ ] for i , ( statementList , ack ) in [ ( i , bodyFn ( item , i ) ) for i , item in enumerate ( items ) ] : statementLists . append ( statementList + [ ( ackSig ( ack ) ) , ] ) If ( ackSig , If ( index . _eq ( itemsCnt - 1 ) , index ( 0 ) ) . Else ( index ( index + 1 ) ) ) return Switch ( index ) . addCases ( enumerate ( statementLists ) ) . Default ( bodyFn ( items [ 0 ] , 0 ) [ 0 ] , ackSig ( True ) )


def sll(sig, howMany) -> RtlSignalBase:
    "Logical shift left"
    width = sig._dtype.bit_length()
    return sig[(width - howMany):]._concat(vec(0, howMany))

def
sll
(
sig
,
howMany
)
->
RtlSignalBase
:
"Logical shift left"
width
=
sig
.
_dtype
.
bit_length
(
)
return
sig
[
(
width
howMany
)
:
]
.
_concat
(
vec
(
0
,
howMany
)
)


def log2ceil(x):
    """
    Returns no of bits required to store x-1
    for example x=8 returns 3
    """

    if not isinstance(x, (int, float)):
        x = int(x)

    if x == 0 or x == 1:
        res = 1
    else:
        res = math.ceil(math.log2(x))

    return hInt(res)

def log2ceil ( x ) : if not isinstance ( x , ( int , float ) ) : x = int ( x ) if x == 0 or x == 1 : res = 1 else : res = math . ceil ( math . log2 ( x ) ) return hInt ( res )

Returns no of bits required to store x - 1 for example x = 8 returns 3


def isPow2(num) -> bool:
    """
    Check if number or constant is power of two
    """
    if not isinstance(num, int):
        num = int(num)
    return num != 0 and ((num & (num - 1)) == 0)

def isPow2 ( num ) -> bool : if not isinstance ( num , int ) : num = int ( num ) return num != 0 and ( ( num & ( num - 1 ) ) == 0 )


def Case(self, caseVal, *statements):
        "c-like case of switch statement"
        assert self.parentStm is None
        caseVal = toHVal(caseVal, self.switchOn._dtype)

        assert isinstance(caseVal, Value), caseVal
        assert caseVal._isFullVld(), "Cmp with invalid value"
        assert caseVal not in self._case_value_index, (
            "Switch statement already has case for value ", caseVal)

        self.rank += 1
        case = []
        self._case_value_index[caseVal] = len(self.cases)
        self.cases.append((caseVal, case))

        cond = self.switchOn._eq(caseVal)
        self._inputs.append(cond)
        cond.endpoints.append(self)

        self._register_stements(statements, case)

        return self


def Default(self, *statements):
        """c-like default of switch statement
        """
        assert self.parentStm is None
        self.rank += 1
        self.default = []
        self._register_stements(statements, self.default)
        return self

def Default ( self , * statements ) : assert self . parentStm is None self . rank += 1 self . default = [ ] self . _register_stements ( statements , self . default ) return self


def vcdRegisterInterfaces(self, obj: Union[Interface, Unit],
                              parent: Optional[VcdVarWritingScope]):
        """
        Register signals from interfaces for Interface or Unit instances
        """
        if hasattr(obj, "_interfaces") and obj._interfaces:
            name = obj._name
            parent_ = self.vcdWriter if parent is None else parent

            subScope = parent_.varScope(name)
            self._obj2scope[obj] = subScope

            with subScope:
                # register all subinterfaces
                for chIntf in obj._interfaces:
                    self.vcdRegisterInterfaces(chIntf, subScope)

                if isinstance(obj, (Unit, SimModel)):
                    # register interfaces from all subunits
                    for u in obj._units:
                        self.vcdRegisterInterfaces(u, subScope)

            return subScope
        else:
            t = obj._dtype
            if isinstance(t, self.supported_type_classes):
                tName, width, formatter = vcdTypeInfoForHType(t)
                try:
                    parent.addVar(obj, getSignalName(obj),
                                  tName, width, formatter)
                except VarAlreadyRegistered:
                    pass

def vcdRegisterInterfaces ( self , obj : Union [ Interface , Unit ] , parent : Optional [ VcdVarWritingScope ] ) : if hasattr ( obj , "_interfaces" ) and obj . _interfaces : name = obj . _name parent_ = self . vcdWriter if parent is None else parent subScope = parent_ . varScope ( name ) self . _obj2scope [ obj ] = subScope with subScope : for chIntf in obj . _interfaces : self . vcdRegisterInterfaces ( chIntf , subScope ) if isinstance ( obj , ( Unit , SimModel ) ) : for u in obj . _units : self . vcdRegisterInterfaces ( u , subScope ) return subScope else : t = obj . _dtype if isinstance ( t , self . supported_type_classes ) : tName , width , formatter = vcdTypeInfoForHType ( t ) try : parent . addVar ( obj , getSignalName ( obj ) , tName , width , formatter ) except VarAlreadyRegistered : pass


def beforeSim(self, simulator, synthesisedUnit):
        """
        This method is called before first step of simulation.
        """
        vcd = self.vcdWriter
        vcd.date(datetime.now())
        vcd.timescale(1)

        self.vcdRegisterInterfaces(synthesisedUnit, None)
        self.vcdRegisterRemainingSignals(synthesisedUnit)

        vcd.enddefinitions()

def beforeSim ( self , simulator , synthesisedUnit ) : vcd = self . vcdWriter vcd . date ( datetime . now ( ) ) vcd . timescale ( 1 ) self . vcdRegisterInterfaces ( synthesisedUnit , None ) self . vcdRegisterRemainingSignals ( synthesisedUnit ) vcd . enddefinitions ( )

This method is called before first step of simulation .


def logChange(self, nowTime, sig, nextVal):
        """
        This method is called for every value change of any signal.
        """
        try:
            self.vcdWriter.logChange(nowTime, sig, nextVal)
        except KeyError:
            # not every signal has to be registered
            pass

def logChange ( self , nowTime , sig , nextVal ) : try : self . vcdWriter . logChange ( nowTime , sig , nextVal ) except KeyError : pass

This method is called for every value change of any signal .


def HWProcess(cls, proc, ctx):
        """
        Serialize HWProcess instance

        :param scope: name scope to prevent name collisions
        """
        body = proc.statements
        childCtx = ctx.withIndent()
        statemets = [cls.asHdl(s, childCtx) for s in body]
        proc.name = ctx.scope.checkedName(proc.name, proc)

        return cls.methodTmpl.render(
            indent=getIndent(ctx.indent),
            name=proc.name,
            statements=statemets
        )

def HWProcess ( cls , proc , ctx ) : body = proc . statements childCtx = ctx . withIndent ( ) statemets = [ cls . asHdl ( s , childCtx ) for s in body ] proc . name = ctx . scope . checkedName ( proc . name , proc ) return cls . methodTmpl . render ( indent = getIndent ( ctx . indent ) , name = proc . name , statements = statemets )


def autoAddAgents(unit):
    """
    Walk all interfaces on unit and instantiate agent for every interface.

    :return: all monitor/driver functions which should be added to simulation
         as processes
    """
    proc = []
    for intf in unit._interfaces:
        if not intf._isExtern:
            continue

        intf._initSimAgent()
        assert intf._ag is not None, intf
        agents = [intf._ag, ]

        if intf._direction == INTF_DIRECTION.MASTER:
            agProcs = list(map(lambda a: a.getMonitors(), agents))
        elif intf._direction == INTF_DIRECTION.SLAVE:
            agProcs = list(map(lambda a: a.getDrivers(), agents))
        else:
            raise NotImplementedError("intf._direction %r for %r" % (
                intf._direction, intf))

        for p in agProcs:
            proc.extend(p)

    return proc

def
autoAddAgents
(
unit
)
:
proc
=
[
]
for
intf
in
unit
.
_interfaces
:
if
not
intf
.
_isExtern
:
continue
intf
.
_initSimAgent
(
)
assert
intf
.
_ag
is
not
,
intf
agents
=
[
intf
.
_ag
,
]
if
intf
.
_direction
==
INTF_DIRECTION
.
MASTER
:
agProcs
=
list
(
map
(
lambda
a
:
a
.
getMonitors
(
)
,
agents
)
)
elif
intf
.
_direction
==
INTF_DIRECTION
.
SLAVE
:
agProcs
=
list
(
map
(
lambda
a
:
a
.
getDrivers
(
)
,
agents
)
)
else
:
raise
NotImplementedError
(
"intf._direction %r for %r"
%
(
intf
.
_direction
,
intf
)
)
for
p
in
agProcs
:
proc
.
extend
(
p
)
return
proc

Walk all interfaces on unit and instantiate agent for every interface .


def _getAssociatedClk(self):
        """
        If interface has associated clk return it otherwise
        try to find clk on parent recursively
        """
        a = self._associatedClk

        if a is not None:
            return a

        p = self._parent
        assert p is not None

        if isinstance(p, UnitBase):
            return getClk(p)
        else:
            return p._getAssociatedClk()

def _getAssociatedClk ( self ) : a = self . _associatedClk if a is not None : return a p = self . _parent assert p is not None if isinstance ( p , UnitBase ) : return getClk ( p ) else : return p . _getAssociatedClk ( )


def distinctBy(iterable, fn):
    """
    uniq operation with key selector
    """
    s = set()
    for i in iterable:
        r = fn(i)
        if r not in s:
            s.add(r)
            yield i

def distinctBy ( iterable , fn ) : s = set ( ) for i in iterable : r = fn ( i ) if r not in s : s . add ( r ) yield i


def groupedby(collection, fn):
    """
    same like itertools.groupby

    :note: This function does not needs initial sorting like itertools.groupby

    :attention: Order of pairs is not deterministic.
    """
    d = {}
    for item in collection:
        k = fn(item)
        try:
            arr = d[k]
        except KeyError:
            arr = []
            d[k] = arr
        arr.append(item)

    yield from d.items()

def groupedby ( collection , fn ) : d = { } for item in collection : k = fn ( item ) try : arr = d [ k ] except KeyError : arr = [ ] d [ k ] = arr arr . append ( item ) yield from d . items ( )


def flatten(iterables, level=inf):
    """
    Flatten nested lists, tuples, generators and maps

    :param level: maximum depth of flattening
    """
    if level >= 0 and isinstance(iterables, (list, tuple, GeneratorType,
                                             map, zip)):
        level -= 1
        for i in iterables:
            yield from flatten(i, level=level)
    else:
        yield iterables

def flatten ( iterables , level = inf ) : if level >= 0 and isinstance ( iterables , ( list , tuple , GeneratorType , map , zip ) ) : level -= 1 for i in iterables : yield from flatten ( i , level = level ) else : yield iterables

Flatten nested lists tuples generators and maps


def _merge_nested_if_from_else(self, ifStm: "IfContainer"):
        """
        Merge nested IfContarner form else branch to this IfContainer
        as elif and else branches
        """
        self.elIfs.append((ifStm.cond, ifStm.ifTrue))
        self.elIfs.extend(ifStm.elIfs)

        self.ifFalse = ifStm.ifFalse

def _merge_nested_if_from_else ( self , ifStm : "IfContainer" ) : self . elIfs . append ( ( ifStm . cond , ifStm . ifTrue ) ) self . elIfs . extend ( ifStm . elIfs ) self . ifFalse = ifStm . ifFalse


def removeUnconnectedSignals(netlist):
    """
    If signal is not driving anything remove it
    """

    toDelete = set()
    toSearch = netlist.signals

    while toSearch:
        _toSearch = set()

        for sig in toSearch:
            if not sig.endpoints:
                try:
                    if sig._interface is not None:
                        # skip interfaces before we want to check them,
                        # they should not be optimized out from design
                        continue
                except AttributeError:
                    pass

                for e in sig.drivers:
                    # drivers of this signal are useless rm them
                    if isinstance(e, Operator):
                        inputs = e.operands
                        if e.result is sig:
                            e.result = None
                    else:
                        inputs = e._inputs
                        netlist.statements.discard(e)

                    for op in inputs:
                        if not isinstance(op, Value):
                            try:
                                op.endpoints.remove(e)
                            except KeyError:
                                # this operator has 2x+ same operand
                                continue

                            _toSearch.add(op)

                toDelete.add(sig)

        if toDelete:
            for sig in toDelete:
                if sig.ctx == netlist:
                    netlist.signals.remove(sig)
                _toSearch.discard(sig)
            toDelete = set()
        toSearch = _toSearch

def removeUnconnectedSignals ( netlist ) : toDelete = set ( ) toSearch = netlist . signals while toSearch : _toSearch = set ( ) for sig in toSearch : if not sig . endpoints : try : if sig . _interface is not None : continue except AttributeError : pass for e in sig . drivers : if isinstance ( e , Operator ) : inputs = e . operands if e . result is sig : e . result = None else : inputs = e . _inputs netlist . statements . discard ( e ) for op in inputs : if not isinstance ( op , Value ) : try : op . endpoints . remove ( e ) except KeyError : continue _toSearch . add ( op ) toDelete . add ( sig ) if toDelete : for sig in toDelete : if sig . ctx == netlist : netlist . signals . remove ( sig ) _toSearch . discard ( sig ) toDelete = set ( ) toSearch = _toSearch


def checkIfIsTooSimple(proc):
    """check if process is just unconditional assignments
       and it is useless to merge them"""
    try:
        a, = proc.statements
        if isinstance(a, Assignment):
            return True
    except ValueError:
        pass
    return False

def checkIfIsTooSimple ( proc ) : try : a , = proc . statements if isinstance ( a , Assignment ) : return True except ValueError : pass return False


def tryToMerge(procA: HWProcess, procB: HWProcess):
    """
    Try merge procB into procA

    :raise IncompatibleStructure: if merge is not possible
    :attention: procA is now result if merge has succeed
    :return: procA which is now result of merge
    """
    if (checkIfIsTooSimple(procA) or
            checkIfIsTooSimple(procB) or
            areSetsIntersets(procA.outputs, procB.sensitivityList) or
            areSetsIntersets(procB.outputs, procA.sensitivityList) or
            not HdlStatement._is_mergable_statement_list(procA.statements, procB.statements)):
        raise IncompatibleStructure()

    procA.statements = HdlStatement._merge_statement_lists(
        procA.statements, procB.statements)

    procA.outputs.extend(procB.outputs)
    procA.inputs.extend(procB.inputs)
    procA.sensitivityList.extend(procB.sensitivityList)

    return procA

def tryToMerge ( procA : HWProcess , procB : HWProcess ) : if ( checkIfIsTooSimple ( procA ) or checkIfIsTooSimple ( procB ) or areSetsIntersets ( procA . outputs , procB . sensitivityList ) or areSetsIntersets ( procB . outputs , procA . sensitivityList ) or not HdlStatement . _is_mergable_statement_list ( procA . statements , procB . statements ) ) : raise IncompatibleStructure ( ) procA . statements = HdlStatement . _merge_statement_lists ( procA . statements , procB . statements ) procA . outputs . extend ( procB . outputs ) procA . inputs . extend ( procB . inputs ) procA . sensitivityList . extend ( procB . sensitivityList ) return procA


def reduceProcesses(processes):
    """
    Try to merge processes as much is possible

    :param processes: list of processes instances
    """
    # sort to make order of merging same deterministic
    processes.sort(key=lambda x: (x.name, maxStmId(x)), reverse=True)
    # now try to reduce processes with nearly same structure of statements into one
    # to minimize number of processes
    for _, procs in groupedby(processes, lambda p: p.rank):
        for iA, pA in enumerate(procs):
            if pA is None:
                continue
            for iB, pB in enumerate(islice(procs, iA + 1, None)):
                if pB is None:
                    continue

                try:
                    pA = tryToMerge(pA, pB)
                except IncompatibleStructure:
                    continue
                procs[iA + 1 + iB] = None
                # procs[iA] = pA

        for p in procs:
            if p is not None:
                yield p

def reduceProcesses ( processes ) : processes . sort ( key = lambda x : ( x . name , maxStmId ( x ) ) , reverse = True ) for _ , procs in groupedby ( processes , lambda p : p . rank ) : for iA , pA in enumerate ( procs ) : if pA is None : continue for iB , pB in enumerate ( islice ( procs , iA + 1 , None ) ) : if pB is None : continue try : pA = tryToMerge ( pA , pB ) except IncompatibleStructure : continue procs [ iA + 1 + iB ] = None for p in procs : if p is not None : yield p


def onWriteReq(self, sim, addr, data):
        """
        on writeReqRecieved in monitor mode
        """
        self.requests.append((WRITE, addr, data))

def onWriteReq ( self , sim , addr , data ) : self . requests . append ( ( WRITE , addr , data ) )


def toRtl(unitOrCls: Unit, name: str=None,
          serializer: GenericSerializer=VhdlSerializer,
          targetPlatform=DummyPlatform(), saveTo: str=None):
    """
    Convert unit to RTL using specified serializer

    :param unitOrCls: unit instance or class, which should be converted
    :param name: name override of top unit (if is None name is derived
        form class name)
    :param serializer: serializer which should be used for to RTL conversion
    :param targetPlatform: metainformatins about target platform, distributed
        on every unit under _targetPlatform attribute
        before Unit._impl() is called
    :param saveTo: directory where files should be stored
        If None RTL is returned as string.
    :raturn: if saveTo returns RTL string else returns list of file names
        which were created
    """
    if not isinstance(unitOrCls, Unit):
        u = unitOrCls()
    else:
        u = unitOrCls

    u._loadDeclarations()
    if name is not None:
        assert isinstance(name, str)
        u._name = name

    globScope = serializer.getBaseNameScope()
    mouduleScopes = {}

    # unitCls : unitobj
    serializedClasses = {}

    # (unitCls, paramsValues) : unitObj
    # where paramsValues are dict name:value
    serializedConfiguredUnits = {}

    doSerialize = True

    createFiles = saveTo is not None
    if createFiles:
        os.makedirs(saveTo, exist_ok=True)
        files = UniqList()
    else:
        codeBuff = []

    for obj in u._toRtl(targetPlatform):
        doSerialize = serializer.serializationDecision(
            obj,
            serializedClasses,
            serializedConfiguredUnits)
        if doSerialize:
            if isinstance(obj, Entity):
                s = globScope.fork(1)
                s.setLevel(2)
                ctx = serializer.getBaseContext()
                ctx.scope = s
                mouduleScopes[obj] = ctx
                ctx.currentUnit = obj.origin

                sc = serializer.Entity(obj, ctx)
                if createFiles:
                    fName = obj.name + serializer.fileExtension
                    fileMode = 'w'

            elif isinstance(obj, Architecture):
                try:
                    ctx = mouduleScopes[obj.entity]
                except KeyError:
                    raise SerializerException(
                        "Entity should be serialized"
                        " before architecture of %s"
                        % (obj.getEntityName()))

                sc = serializer.Architecture(obj, ctx)
                if createFiles:
                    fName = obj.getEntityName() + serializer.fileExtension
                    fileMode = 'a'
            else:
                if hasattr(obj, "_hdlSources"):
                    for fn in obj._hdlSources:
                        if isinstance(fn, str):
                            shutil.copy2(fn, saveTo)
                            files.append(fn)
                            continue
                else:
                    sc = serializer.asHdl(obj)

            if sc:
                if createFiles:
                    fp = os.path.join(saveTo, fName)
                    files.append(fp)
                    with open(fp, fileMode) as f:
                        if fileMode == 'a':
                            f.write("\n")

                        f.write(
                            serializer.formatter(sc)
                        )
                else:
                    codeBuff.append(sc)

        elif not createFiles:
            try:
                name = '"%s"' % obj.name
            except AttributeError:
                name = ""
            codeBuff.append(serializer.comment(
                "Object of class %s, %s was not serialized as specified" % (
                    obj.__class__.__name__, name)))

    if createFiles:
        return files
    else:
        return serializer.formatter(
            "\n".join(codeBuff)
        )


def name_for_process_and_mark_outputs(statements: List[HdlStatement])\
        -> str:
    """
    Resolve name for process and mark outputs of statemens as not hidden
    """
    out_names = []
    for stm in statements:
        for sig in stm._outputs:
            if not sig.hasGenericName:
                out_names.append(sig.name)

    if out_names:
        return min(out_names)
    else:
        return ""

def name_for_process_and_mark_outputs ( statements : List [ HdlStatement ] ) -> str : out_names = [ ] for stm in statements : for sig in stm . _outputs : if not sig . hasGenericName : out_names . append ( sig . name ) if out_names : return min ( out_names ) else : return ""


def cut_off_drivers_of(dstSignal, statements):
    """
    Cut off drivers from statements
    """
    separated = []
    stm_filter = []
    for stm in statements:
        stm._clean_signal_meta()
        d = stm._cut_off_drivers_of(dstSignal)
        if d is not None:
            separated.append(d)

        f = d is not stm
        stm_filter.append(f)

    return list(compress(statements, stm_filter)), separated

def cut_off_drivers_of ( dstSignal , statements ) : separated = [ ] stm_filter = [ ] for stm in statements : stm . _clean_signal_meta ( ) d = stm . _cut_off_drivers_of ( dstSignal ) if d is not None : separated . append ( d ) f = d is not stm stm_filter . append ( f ) return list ( compress ( statements , stm_filter ) ) , separated


def sig(self, name, dtype=BIT, clk=None, syncRst=None, defVal=None):
        """
        Create new signal in this context

        :param clk: clk signal, if specified signal is synthesized
            as SyncSignal
        :param syncRst: synchronous reset signal
        """
        if isinstance(defVal, RtlSignal):
            assert defVal._const, \
                "Initial value of register has to be constant"
            _defVal = defVal._auto_cast(dtype)
        elif isinstance(defVal, Value):
            _defVal = defVal._auto_cast(dtype)
        elif isinstance(defVal, InterfaceBase):
            _defVal = defVal._sig
        else:
            _defVal = dtype.fromPy(defVal)

        if clk is not None:
            s = RtlSyncSignal(self, name, dtype, _defVal)
            if syncRst is not None and defVal is None:
                raise SigLvlConfErr(
                    "Probably forgotten default value on sync signal %s", name)
            if syncRst is not None:
                r = If(syncRst._isOn(),
                       RtlSignal.__call__(s, _defVal)
                       ).Else(
                    RtlSignal.__call__(s, s.next)
                )
            else:
                r = [RtlSignal.__call__(s, s.next)]

            If(clk._onRisingEdge(),
               r
               )
        else:
            if syncRst:
                raise SigLvlConfErr(
                    "Signal %s has reset but has no clk" % name)
            s = RtlSignal(self, name, dtype, defVal=_defVal)

        self.signals.add(s)

        return s


def synthesize(self, name, interfaces, targetPlatform):
        """
        Build Entity and Architecture instance out of netlist representation
        """
        ent = Entity(name)
        ent._name = name + "_inst"  # instance name

        # create generics
        for _, v in self.params.items():
            ent.generics.append(v)

        # interface set for faster lookup
        if isinstance(interfaces, set):
            intfSet = interfaces
        else:
            intfSet = set(interfaces)

        # create ports
        for s in interfaces:
            pi = portItemfromSignal(s, ent)
            pi.registerInternSig(s)
            ent.ports.append(pi)
            s.hidden = False

        removeUnconnectedSignals(self)
        markVisibilityOfSignals(self, name, self.signals, intfSet)

        for proc in targetPlatform.beforeHdlArchGeneration:
            proc(self)

        arch = Architecture(ent)
        for p in statements_to_HWProcesses(self.statements):
            arch.processes.append(p)

        # add signals, variables etc. in architecture
        for s in self.signals:
            if s not in intfSet and not s.hidden:
                arch.variables.append(s)

        # instantiate subUnits in architecture
        for u in self.subUnits:
            arch.componentInstances.append(u)

        # add components in architecture
        for su in distinctBy(self.subUnits, lambda x: x.name):
            arch.components.append(su)

        self.synthesised = True

        return [ent, arch]

def synthesize ( self , name , interfaces , targetPlatform ) : ent = Entity ( name ) ent . _name = name + "_inst" for _ , v in self . params . items ( ) : ent . generics . append ( v ) if isinstance ( interfaces , set ) : intfSet = interfaces else : intfSet = set ( interfaces ) for s in interfaces : pi = portItemfromSignal ( s , ent ) pi . registerInternSig ( s ) ent . ports . append ( pi ) s . hidden = False removeUnconnectedSignals ( self ) markVisibilityOfSignals ( self , name , self . signals , intfSet ) for proc in targetPlatform . beforeHdlArchGeneration : proc ( self ) arch = Architecture ( ent ) for p in statements_to_HWProcesses ( self . statements ) : arch . processes . append ( p ) for s in self . signals : if s not in intfSet and not s . hidden : arch . variables . append ( s ) for u in self . subUnits : arch . componentInstances . append ( u ) for su in distinctBy ( self . subUnits , lambda x : x . name ) : arch . components . append ( su ) self . synthesised = True return [ ent , arch ]


def getMaxStmIdForStm(stm):
    """
    Get maximum _instId from all assigments in statement
    """
    maxId = 0
    if isinstance(stm, Assignment):
        return stm._instId
    elif isinstance(stm, WaitStm):
        return maxId
    else:
        for _stm in stm._iter_stms():
            maxId = max(maxId, getMaxStmIdForStm(_stm))
        return maxId

def getMaxStmIdForStm ( stm ) : maxId = 0 if isinstance ( stm , Assignment ) : return stm . _instId elif isinstance ( stm , WaitStm ) : return maxId else : for _stm in stm . _iter_stms ( ) : maxId = max ( maxId , getMaxStmIdForStm ( _stm ) ) return maxId


def maxStmId(proc):
    """
    get max statement id,
    used for sorting of processes in architecture
    """
    maxId = 0
    for stm in proc.statements:
        maxId = max(maxId, getMaxStmIdForStm(stm))
    return maxId

def maxStmId ( proc ) : maxId = 0 for stm in proc . statements : maxId = max ( maxId , getMaxStmIdForStm ( stm ) ) return maxId

get max statement id used for sorting of processes in architecture


def doWrite(self, sim, data):
        """write data to interface"""
        sim.write(data, self.intf.data)

def doWrite ( self , sim , data ) : sim . write ( data , self . intf . data )


def _m(self):
        """
        Note that this interface will be master

        :return: self
        """
        assert not hasattr(self, "_interfaces") or not self._interfaces, \
            "Too late to change direction of interface"
        self._direction = DIRECTION.asIntfDirection(DIRECTION.opposite(self._masterDir))

        return self


def _loadDeclarations(self):
        """
        load declaratoins from _declr method
        This function is called first for parent and then for children
        """
        if not hasattr(self, "_interfaces"):
            self._interfaces = []
        self._setAttrListener = self._declrCollector
        self._declr()
        self._setAttrListener = None

        for i in self._interfaces:
            i._isExtern = self._isExtern
            i._loadDeclarations()

        for p in self._params:
            p.setReadOnly()

        if self._isExtern:
            # direction from inside of unit (reverset compared to outside direction)
            if self._direction == INTF_DIRECTION.UNKNOWN:
                self._direction = INTF_DIRECTION.MASTER
            self._setDirectionsLikeIn(self._direction)

def _loadDeclarations ( self ) : if not hasattr ( self , "_interfaces" ) : self . _interfaces = [ ] self . _setAttrListener = self . _declrCollector self . _declr ( ) self . _setAttrListener = None for i in self . _interfaces : i . _isExtern = self . _isExtern i . _loadDeclarations ( ) for p in self . _params : p . setReadOnly ( ) if self . _isExtern : if self . _direction == INTF_DIRECTION . UNKNOWN : self . _direction = INTF_DIRECTION . MASTER self . _setDirectionsLikeIn ( self . _direction )


def _signalsForInterface(self, context, prefix='', typeTransform=None):
        """
        generate _sig for each interface which has no subinterface
        if already has _sig return it instead

        :param context: instance of RtlNetlist where signals should be created
        :param prefix: name prefix for created signals
        :param typeTransform: optional function (type) returns modified type
            for signal
        """
        sigs = []
        if self._interfaces:
            for intf in self._interfaces:
                sigs.extend(
                    intf._signalsForInterface(context, prefix,
                                              typeTransform=typeTransform))
        else:
            if hasattr(self, '_sig'):
                sigs = [self._sig]
            else:
                t = self._dtype
                if typeTransform is not None:
                    t = typeTransform(t)

                s = context.sig(prefix + self._getPhysicalName(), t)
                s._interface = self
                self._sig = s

                if hasattr(self, '_boundedEntityPort'):
                    self._boundedEntityPort.connectSig(self._sig)
                sigs = [s]

        return sigs

def _signalsForInterface ( self , context , prefix = '' , typeTransform = None ) : sigs = [ ] if self . _interfaces : for intf in self . _interfaces : sigs . extend ( intf . _signalsForInterface ( context , prefix , typeTransform = typeTransform ) ) else : if hasattr ( self , '_sig' ) : sigs = [ self . _sig ] else : t = self . _dtype if typeTransform is not None : t = typeTransform ( t ) s = context . sig ( prefix + self . _getPhysicalName ( ) , t ) s . _interface = self self . _sig = s if hasattr ( self , '_boundedEntityPort' ) : self . _boundedEntityPort . connectSig ( self . _sig ) sigs = [ s ] return sigs


def _getPhysicalName(self):
        """Get name in HDL """
        if hasattr(self, "_boundedEntityPort"):
            return self._boundedEntityPort.name
        else:
            return self._getFullName().replace('.', self._NAME_SEPARATOR)

def _getPhysicalName ( self ) : if hasattr ( self , "_boundedEntityPort" ) : return self . _boundedEntityPort . name else : return self . _getFullName ( ) . replace ( '.' , self . _NAME_SEPARATOR )


def _bit_length(self):
        """Sum of all width of interfaces in this interface"""
        try:
            interfaces = self._interfaces
        except AttributeError:
            interfaces = None

        if interfaces is None:
            # not loaded interface
            _intf = self._clone()
            _intf._loadDeclarations()
            interfaces = _intf._interfaces

        if interfaces:
            w = 0
            for i in interfaces:
                w += i._bit_length()
            return w
        else:
            return self._dtype.bit_length()

def _bit_length ( self ) : try : interfaces = self . _interfaces except AttributeError : interfaces = None if interfaces is None : _intf = self . _clone ( ) _intf . _loadDeclarations ( ) interfaces = _intf . _interfaces if interfaces : w = 0 for i in interfaces : w += i . _bit_length ( ) return w else : return self . _dtype . bit_length ( )


def sensitivityByOp(op):
    """
    get sensitivity type for operator
    """
    if op == AllOps.RISING_EDGE:
        return SENSITIVITY.RISING
    elif op == AllOps.FALLING_EDGE:
        return SENSITIVITY.FALLING
    else:
        raise TypeError()

def sensitivityByOp ( op ) : if op == AllOps . RISING_EDGE : return SENSITIVITY . RISING elif op == AllOps . FALLING_EDGE : return SENSITIVITY . FALLING else : raise TypeError ( )


def eval(self, operator, simulator=None):
        """Load all operands and process them by self._evalFn"""
        def getVal(v):
            while not isinstance(v, Value):
                v = v._val

            return v

        operands = list(map(getVal, operator.operands))

        if isEventDependentOp(operator.operator):
            operands.append(simulator.now)
        elif operator.operator == AllOps.IntToBits:
            operands.append(operator.result._dtype)

        return self._evalFn(*operands)

def eval ( self , operator , simulator = None ) : def getVal ( v ) : while not isinstance ( v , Value ) : v = v . _val return v operands = list ( map ( getVal , operator . operands ) ) if isEventDependentOp ( operator . operator ) : operands . append ( simulator . now ) elif operator . operator == AllOps . IntToBits : operands . append ( operator . result . _dtype ) return self . _evalFn ( * operands )

Load all operands and process them by self . _evalFn


def convertBits(self, sigOrVal, toType):
    """
    Cast signed-unsigned, to int or bool
    """
    if isinstance(sigOrVal, Value):
        return convertBits__val(self, sigOrVal, toType)
    elif isinstance(toType, HBool):
        if self.bit_length() == 1:
            v = 0 if sigOrVal._dtype.negated else 1
            return sigOrVal._eq(self.getValueCls().fromPy(v, self))
    elif isinstance(toType, Bits):
        if self.bit_length() == toType.bit_length():
            return sigOrVal._convSign(toType.signed)
    elif toType == INT:
        return Operator.withRes(AllOps.BitsToInt, [sigOrVal], toType)

    return default_auto_cast_fn(self, sigOrVal, toType)

def convertBits ( self , sigOrVal , toType ) : if isinstance ( sigOrVal , Value ) : return convertBits__val ( self , sigOrVal , toType ) elif isinstance ( toType , HBool ) : if self . bit_length ( ) == 1 : v = 0 if sigOrVal . _dtype . negated else 1 return sigOrVal . _eq ( self . getValueCls ( ) . fromPy ( v , self ) ) elif isinstance ( toType , Bits ) : if self . bit_length ( ) == toType . bit_length ( ) : return sigOrVal . _convSign ( toType . signed ) elif toType == INT : return Operator . withRes ( AllOps . BitsToInt , [ sigOrVal ] , toType ) return default_auto_cast_fn ( self , sigOrVal , toType )


def reinterpret_bits_to_hstruct(sigOrVal, hStructT):
    """
    Reinterpret signal of type Bits to signal of type HStruct
    """
    container = hStructT.fromPy(None)
    offset = 0
    for f in hStructT.fields:
        t = f.dtype
        width = t.bit_length()
        if f.name is not None:
            s = sigOrVal[(width + offset):offset]
            s = s._reinterpret_cast(t)
            setattr(container, f.name, s)

        offset += width

    return container

def reinterpret_bits_to_hstruct ( sigOrVal , hStructT ) : container = hStructT . fromPy ( None ) offset = 0 for f in hStructT . fields : t = f . dtype width = t . bit_length ( ) if f . name is not None : s = sigOrVal [ ( width + offset ) : offset ] s = s . _reinterpret_cast ( t ) setattr ( container , f . name , s ) offset += width return container


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

def fullWordCnt ( self , start : int , end : int ) : assert end >= start , ( start , end ) gap = max ( 0 , ( end - start ) - ( start % self . wordWidth ) ) return gap // self . wordWidth


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)

def groupByWordIndex ( self , transaction : 'TransTmpl' , offset : int ) : 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 )


def pprintInterface(intf, prefix="", indent=0, file=sys.stdout):
    """
    Pretty print interface
    """
    try:
        s = intf._sig
    except AttributeError:
        s = ""
    if s is not "":
        s = " " + repr(s)

    file.write("".join([getIndent(indent), prefix, repr(intf._getFullName()),
                        s]))
    file.write("\n")

    if isinstance(intf, HObjList):
        for i, p in enumerate(intf):
            # interfaces have already name of this array and index in it's name
            pprintInterface(p, prefix=prefix, indent=indent + 1, file=file)
    else:
        for i in intf._interfaces:
            pprintInterface(i, indent=indent + 1, file=file)

def
pprintInterface
(
intf
,
prefix
=
""
,
indent
=
0
,
file
=
sys
.
stdout
)
:
try
:
s
=
intf
.
_sig
except
AttributeError
:
s
=
""
if
s
is
not
""
:
s
=
" "
+
repr
(
s
)
file
.
write
(
""
.
join
(
[
getIndent
(
indent
)
,
prefix
,
repr
(
intf
.
_getFullName
(
)
)
,
s
]
)
)
file
.
write
(
"\n"
)
if
isinstance
(
intf
,
HObjList
)
:
for
i
,
p
in
enumerate
(
intf
)
:
pprintInterface
(
p
,
prefix
=
prefix
,
indent
=
indent
+
1
,
file
=
file
)
else
:
for
i
in
intf
.
_interfaces
:
pprintInterface
(
i
,
indent
=
indent
+
1
,
file
=
file
)


def framesFromTransTmpl(transaction: 'TransTmpl',
                            wordWidth: int,
                            maxFrameLen: Union[int, float]=inf,
                            maxPaddingWords: Union[int, float]=inf,
                            trimPaddingWordsOnStart: bool=False,
                            trimPaddingWordsOnEnd: bool=False) -> Generator[
                                'FrameTmpl', None, None]:
        """
        Convert transaction template into FrameTmpls

        :param transaction: transaction template used which are FrameTmpls
            created from
        :param wordWidth: width of data signal in target interface
            where frames will be used
        :param maxFrameLen: maximum length of frame in bits,
            if exceeded another frame will be created
        :param maxPaddingWords: maximum of continual padding words in frame,
            if exceed frame is split and words are cut of
        :attention: if maxPaddingWords<inf trimPaddingWordsOnEnd
            or trimPaddingWordsOnStart has to be True
            to decide where padding should be trimmed
        :param trimPaddingWordsOnStart: trim padding from start of frame
            at word granularity
        :param trimPaddingWordsOnEnd: trim padding from end of frame
            at word granularity
        """
        isFirstInFrame = True
        partsPending = False

        startOfThisFrame = 0
        assert maxFrameLen > 0
        assert maxPaddingWords >= 0
        if maxPaddingWords < inf:
            assert trimPaddingWordsOnStart or trimPaddingWordsOnEnd, \
                "Padding has to be cut off somewhere"

        it = TransTmplWordIterator(wordWidth)
        lastWordI = 0
        endOfThisFrame = maxFrameLen
        parts = []
        for wordI, word in it.groupByWordIndex(transaction, 0):
            if wordI * wordWidth >= endOfThisFrame:
                # now in first+ word behind the frame
                # cut off padding at end of frame
                paddingWords = wordI - lastWordI
                if trimPaddingWordsOnEnd and paddingWords > maxPaddingWords:
                    # cut off padding and align end of frame to word
                    _endOfThisFrame = (lastWordI + 1) * wordWidth
                else:
                    _endOfThisFrame = wordI * wordWidth

                yield FrameTmpl(transaction,
                                wordWidth,
                                startOfThisFrame,
                                _endOfThisFrame,
                                parts)

                # prepare for start of new frame
                parts = []
                isFirstInFrame = True
                partsPending = False
                # start on new word
                startOfThisFrame = _endOfThisFrame
                endOfThisFrame = startOfThisFrame + maxFrameLen
                lastWordI = wordI

            # check if padding at potential end of frame can be cut off
            if (not isFirstInFrame
                    and trimPaddingWordsOnEnd
                    and wordI - lastWordI > 1):
                # there is too much continual padding,
                # cut it out and start new frame
                _endOfThisFrame = (lastWordI + 1) * wordWidth
                yield FrameTmpl(transaction,
                                wordWidth,
                                startOfThisFrame,
                                _endOfThisFrame,
                                parts)

                # prepare for start of new frame
                parts = []
                isFirstInFrame = True
                partsPending = False
                # start on new word
                startOfThisFrame = _endOfThisFrame
                endOfThisFrame = startOfThisFrame + maxFrameLen
                lastWordI = wordI - 1

            if isFirstInFrame:
                partsPending = True
                isFirstInFrame = False
                # cut off padding at start of frame
                paddingWords = wordI - lastWordI
                if trimPaddingWordsOnStart and paddingWords > maxPaddingWords:
                    startOfThisFrame += paddingWords * wordWidth

                endOfThisFrame = startOfThisFrame + maxFrameLen

            # resolve end of this part
            parts.extend(word)
            lastWordI = wordI

        # reminder in "parts" after last iteration
        endOfThisFrame = transaction.bitAddrEnd
        withPadding = not (trimPaddingWordsOnEnd or trimPaddingWordsOnStart)
        if partsPending or (withPadding
                            and endOfThisFrame != startOfThisFrame):
            # cut off padding at end of frame
            endOfLastWord = (lastWordI + 1) * wordWidth
            if endOfThisFrame < endOfLastWord:
                endOfThisFrame = endOfLastWord
            else:
                paddingWords = it.fullWordCnt(endOfLastWord, endOfThisFrame)
                if trimPaddingWordsOnEnd and paddingWords > maxPaddingWords:
                    endOfThisFrame -= paddingWords * wordWidth
                    # align end of frame to word
            endOfThisFrame = min(startOfThisFrame +
                                 maxFrameLen, endOfThisFrame)

            yield FrameTmpl(transaction,
                            wordWidth,
                            startOfThisFrame,
                            endOfThisFrame,
                            parts)
            parts = []
            startOfThisFrame = endOfThisFrame

        # final padding on the end
        while withPadding and startOfThisFrame < transaction.bitAddrEnd:
            endOfThisFrame = min(startOfThisFrame +
                                 maxFrameLen, transaction.bitAddrEnd)

            yield FrameTmpl(transaction,
                            wordWidth,
                            startOfThisFrame,
                            endOfThisFrame,
                            [])

            startOfThisFrame = endOfThisFrame

def
framesFromTransTmpl
(
transaction
:
'TransTmpl'
,
wordWidth
:
int
,
maxFrameLen
:
Union
[
int
,
float
]
=
inf
,
maxPaddingWords
:
Union
[
int
,
float
]
=
inf
,
trimPaddingWordsOnStart
:
bool
=
False
,
trimPaddingWordsOnEnd
:
bool
=
False
)
->
Generator
[
'FrameTmpl'
,
,
]
:
isFirstInFrame
=
True
partsPending
=
False
startOfThisFrame
=
0
assert
maxFrameLen
>
0
assert
maxPaddingWords
>=
0
if
maxPaddingWords
<
inf
:
assert
trimPaddingWordsOnStart
or
trimPaddingWordsOnEnd
,
"Padding has to be cut off somewhere"
it
=
TransTmplWordIterator
(
wordWidth
)
lastWordI
=
0
endOfThisFrame
=
maxFrameLen
parts
=
[
]
for
wordI
,
word
in
it
.
groupByWordIndex
(
transaction
,
0
)
:
if
wordI
*
wordWidth
>=
endOfThisFrame
:
paddingWords
=
wordI
lastWordI
if
trimPaddingWordsOnEnd
and
paddingWords
>
maxPaddingWords
:
_endOfThisFrame
=
(
lastWordI
+
1
)
*
wordWidth
else
:
_endOfThisFrame
=
wordI
*
wordWidth
yield
FrameTmpl
(
transaction
,
wordWidth
,
startOfThisFrame
,
_endOfThisFrame
,
parts
)
parts
=
[
]
isFirstInFrame
=
True
partsPending
=
False
startOfThisFrame
=
_endOfThisFrame
endOfThisFrame
=
startOfThisFrame
+
maxFrameLen
lastWordI
=
wordI
if
(
not
isFirstInFrame
and
trimPaddingWordsOnEnd
and
wordI
lastWordI
>
1
)
:
_endOfThisFrame
=
(
lastWordI
+
1
)
*
wordWidth
yield
FrameTmpl
(
transaction
,
wordWidth
,
startOfThisFrame
,
_endOfThisFrame
,
parts
)
parts
=
[
]
isFirstInFrame
=
True
partsPending
=
False
startOfThisFrame
=
_endOfThisFrame
endOfThisFrame
=
startOfThisFrame
+
maxFrameLen
lastWordI
=
wordI
1
if
isFirstInFrame
:
partsPending
=
True
isFirstInFrame
=
False
paddingWords
=
wordI
lastWordI
if
trimPaddingWordsOnStart
and
paddingWords
>
maxPaddingWords
:
startOfThisFrame
+=
paddingWords
*
wordWidth
endOfThisFrame
=
startOfThisFrame
+
maxFrameLen
parts
.
extend
(
word
)
lastWordI
=
wordI
endOfThisFrame
=
transaction
.
bitAddrEnd
withPadding
=
not
(
trimPaddingWordsOnEnd
or
trimPaddingWordsOnStart
)
if
partsPending
or
(
withPadding
and
endOfThisFrame
!=
startOfThisFrame
)
:
endOfLastWord
=
(
lastWordI
+
1
)
*
wordWidth
if
endOfThisFrame
<
endOfLastWord
:
endOfThisFrame
=
endOfLastWord
else
:
paddingWords
=
it
.
fullWordCnt
(
endOfLastWord
,
endOfThisFrame
)
if
trimPaddingWordsOnEnd
and
paddingWords
>
maxPaddingWords
:
endOfThisFrame
-=
paddingWords
*
wordWidth
endOfThisFrame
=
min
(
startOfThisFrame
+
maxFrameLen
,
endOfThisFrame
)
yield
FrameTmpl
(
transaction
,
wordWidth
,
startOfThisFrame
,
endOfThisFrame
,
parts
)
parts
=
[
]
startOfThisFrame
=
endOfThisFrame
while
withPadding
and
startOfThisFrame
<
transaction
.
bitAddrEnd
:
endOfThisFrame
=
min
(
startOfThisFrame
+
maxFrameLen
,
transaction
.
bitAddrEnd
)
yield
FrameTmpl
(
transaction
,
wordWidth
,
startOfThisFrame
,
endOfThisFrame
,
[
]
)
startOfThisFrame
=
endOfThisFrame


def walkWords(self, showPadding: bool=False):
        """
        Walk enumerated words in this frame

        :attention: not all indexes has to be present, only words
            with items will be generated when not showPadding
        :param showPadding: padding TransParts are also present
        :return: generator of tuples (wordIndex, list of TransParts
            in this word)
        """
        wIndex = 0
        lastEnd = self.startBitAddr
        parts = []
        for p in self.parts:
            end = p.startOfPart
            if showPadding and end != lastEnd:
                # insert padding
                while end != lastEnd:
                    assert end >= lastEnd, (end, lastEnd)
                    endOfWord = ceil(
                        (lastEnd + 1) / self.wordWidth) * self.wordWidth
                    endOfPadding = min(endOfWord, end)
                    _p = TransPart(self, None, lastEnd, endOfPadding, 0)
                    parts.append(_p)

                    if endOfPadding >= endOfWord:
                        yield (wIndex, parts)
                        wIndex += 1
                        parts = []

                    lastEnd = endOfPadding

            if self._wordIndx(lastEnd) != self._wordIndx(p.startOfPart):
                yield (wIndex, parts)

                wIndex += 1
                parts = []
                lastEnd = p.endOfPart

            parts.append(p)
            lastEnd = p.endOfPart
            if lastEnd % self.wordWidth == 0:
                yield (wIndex, parts)

                wIndex += 1
                parts = []

        if showPadding and (parts
                            or lastEnd != self.endBitAddr
                            or lastEnd % self.wordWidth != 0):
            # align end to end of last word
            end = ceil(self.endBitAddr / self.wordWidth) * self.wordWidth
            while end != lastEnd:
                assert end >= lastEnd, (end, lastEnd)
                endOfWord = ((lastEnd // self.wordWidth) + 1) * self.wordWidth
                endOfPadding = min(endOfWord, end)
                _p = TransPart(self, None, lastEnd, endOfPadding, 0)
                _p.parent = self
                parts.append(_p)

                if endOfPadding >= endOfWord:
                    yield (wIndex, parts)
                    wIndex += 1
                    parts = []

                lastEnd = endOfPadding

            if parts:
                # in the case end of frame is not aligned to end of word
                yield (wIndex, parts)

def walkWords ( self , showPadding : bool = False ) : wIndex = 0 lastEnd = self . startBitAddr parts = [ ] for p in self . parts : end = p . startOfPart if showPadding and end != lastEnd : while end != lastEnd : assert end >= lastEnd , ( end , lastEnd ) endOfWord = ceil ( ( lastEnd + 1 ) / self . wordWidth ) * self . wordWidth endOfPadding = min ( endOfWord , end ) _p = TransPart ( self , None , lastEnd , endOfPadding , 0 ) parts . append ( _p ) if endOfPadding >= endOfWord : yield ( wIndex , parts ) wIndex += 1 parts = [ ] lastEnd = endOfPadding if self . _wordIndx ( lastEnd ) != self . _wordIndx ( p . startOfPart ) : yield ( wIndex , parts ) wIndex += 1 parts = [ ] lastEnd = p . endOfPart parts . append ( p ) lastEnd = p . endOfPart if lastEnd % self . wordWidth == 0 : yield ( wIndex , parts ) wIndex += 1 parts = [ ] if showPadding and ( parts or lastEnd != self . endBitAddr or lastEnd % self . wordWidth != 0 ) : end = ceil ( self . endBitAddr / self . wordWidth ) * self . wordWidth while end != lastEnd : assert end >= lastEnd , ( end , lastEnd ) endOfWord = ( ( lastEnd // self . wordWidth ) + 1 ) * self . wordWidth endOfPadding = min ( endOfWord , end ) _p = TransPart ( self , None , lastEnd , endOfPadding , 0 ) _p . parent = self parts . append ( _p ) if endOfPadding >= endOfWord : yield ( wIndex , parts ) wIndex += 1 parts = [ ] lastEnd = endOfPadding if parts : yield ( wIndex , parts )


def packData(self, data):
        """
        Pack data into list of BitsVal of specified dataWidth

        :param data: dict of values for struct fields {fieldName: value}

        :return: list of BitsVal which are representing values of words
        """
        typeOfWord = simBitsT(self.wordWidth, None)
        fieldToVal = self._fieldToTPart
        if fieldToVal is None:
            fieldToVal = self._fieldToTPart = self.fieldToDataDict(
                self.origin.dtype,
                data,
                {})

        for _, transParts in self.walkWords(showPadding=True):
            actualVldMask = 0
            actualVal = 0
            for tPart in transParts:
                high, low = tPart.getBusWordBitRange()
                fhigh, flow = tPart.getFieldBitRange()
                if not tPart.isPadding:
                    val = fieldToVal.get(tPart.tmpl.origin, None)
                else:
                    val = None

                if val is None:
                    newBits = 0
                    vld = 0
                else:
                    newBits = selectBitRange(val, flow, fhigh - flow)
                    vld = mask(high - low) << low

                actualVal = setBitRange(actualVal, low, high - low, newBits)
                actualVldMask = setBitRange(actualVal, low, high - low, vld)

            yield typeOfWord.getValueCls()(actualVal, typeOfWord,
                                           actualVldMask, -1)

def packData ( self , data ) : typeOfWord = simBitsT ( self . wordWidth , None ) fieldToVal = self . _fieldToTPart if fieldToVal is None : fieldToVal = self . _fieldToTPart = self . fieldToDataDict ( self . origin . dtype , data , { } ) for _ , transParts in self . walkWords ( showPadding = True ) : actualVldMask = 0 actualVal = 0 for tPart in transParts : high , low = tPart . getBusWordBitRange ( ) fhigh , flow = tPart . getFieldBitRange ( ) if not tPart . isPadding : val = fieldToVal . get ( tPart . tmpl . origin , None ) else : val = None if val is None : newBits = 0 vld = 0 else : newBits = selectBitRange ( val , flow , fhigh - flow ) vld = mask ( high - low ) << low actualVal = setBitRange ( actualVal , low , high - low , newBits ) actualVldMask = setBitRange ( actualVal , low , high - low , vld ) yield typeOfWord . getValueCls ( ) ( actualVal , typeOfWord , actualVldMask , - 1 )


def _clean_signal_meta(self):
        """
        Clean informations about enclosure for outputs and sensitivity
        of this statement
        """
        self._enclosed_for = None
        self._sensitivity = None
        for stm in self._iter_stms():
            stm._clean_signal_meta()

def _clean_signal_meta ( self ) : self . _enclosed_for = None self . _sensitivity = None for stm in self . _iter_stms ( ) : stm . _clean_signal_meta ( )


def _discover_enclosure_for_statements(statements: List['HdlStatement'],
                                           outputs: List['HdlStatement']):
        """
        Discover enclosure for list of statements

        :param statements: list of statements in one code branch
        :param outputs: list of outputs which should be driven from this statement list
        :return: set of signals for which this statement list have always some driver
            (is enclosed)
        """
        result = set()
        if not statements:
            return result

        for stm in statements:
            stm._discover_enclosure()

        for o in outputs:
            has_driver = False

            for stm in statements:
                if o in stm._outputs:
                    assert not has_driver
                    has_driver = False
                    if o in stm._enclosed_for:
                        result.add(o)
                else:
                    pass

        return result

def _discover_enclosure_for_statements ( statements : List [ 'HdlStatement' ] , outputs : List [ 'HdlStatement' ] ) : result = set ( ) if not statements : return result for stm in statements : stm . _discover_enclosure ( ) for o in outputs : has_driver = False for stm in statements : if o in stm . _outputs : assert not has_driver has_driver = False if o in stm . _enclosed_for : result . add ( o ) else : pass return result


def _discover_sensitivity_seq(self,
                                  signals: List[RtlSignalBase],
                                  seen: set, ctx: SensitivityCtx)\
            -> None:
        """
        Discover sensitivity for list of signals

        """
        casualSensitivity = set()
        for s in signals:
            s._walk_sensitivity(casualSensitivity, seen, ctx)
            if ctx.contains_ev_dependency:
                break

        # if event dependent sensitivity found do not add other sensitivity
        if not ctx.contains_ev_dependency:
            ctx.extend(casualSensitivity)

def _discover_sensitivity_seq ( self , signals : List [ RtlSignalBase ] , seen : set , ctx : SensitivityCtx ) -> None : casualSensitivity = set ( ) for s in signals : s . _walk_sensitivity ( casualSensitivity , seen , ctx ) if ctx . contains_ev_dependency : break if not ctx . contains_ev_dependency : ctx . extend ( casualSensitivity )


def _get_rtl_context(self):
        """
        get RtlNetlist context from signals
        """
        for sig in chain(self._inputs, self._outputs):
            if sig.ctx:
                return sig.ctx
            else:
                # Param instances does not have context
                continue
        raise HwtSyntaxError(
            "Statement does not have any signal in any context", self)


def _on_reduce(self, self_reduced: bool, io_changed: bool,
                   result_statements: List["HdlStatement"]) -> None:
        """
        Update signal IO after reuce atempt

        :param self_reduced: if True this object was reduced
        :param io_changed: if True IO of this object may changed
            and has to be updated
        :param result_statements: list of statements which are result
            of reduce operation on this statement
        """

        parentStm = self.parentStm
        if self_reduced:
            was_top = parentStm is None
            # update signal drivers/endpoints
            if was_top:
                # disconnect self from signals
                ctx = self._get_rtl_context()
                ctx.statements.remove(self)
                ctx.statements.update(result_statements)

                for i in self._inputs:
                    i.endpoints.discard(self)
                for o in self._outputs:
                    o.drivers.remove(self)

            for stm in result_statements:
                stm.parentStm = parentStm
                if parentStm is None:
                    # conect signals to child statements
                    for inp in stm._inputs:
                        inp.endpoints.append(stm)
                    for outp in stm._outputs:
                        outp.drivers.append(stm)
        else:
            # parent has to update it's inputs/outputs
            if io_changed:
                self._inputs = UniqList()
                self._outputs = UniqList()
                self._collect_io()

def _on_reduce ( self , self_reduced : bool , io_changed : bool , result_statements : List [ "HdlStatement" ] ) -> None : parentStm = self . parentStm if self_reduced : was_top = parentStm is None if was_top : ctx = self . _get_rtl_context ( ) ctx . statements . remove ( self ) ctx . statements . update ( result_statements ) for i in self . _inputs : i . endpoints . discard ( self ) for o in self . _outputs : o . drivers . remove ( self ) for stm in result_statements : stm . parentStm = parentStm if parentStm is None : for inp in stm . _inputs : inp . endpoints . append ( stm ) for outp in stm . _outputs : outp . drivers . append ( stm ) else : if io_changed : self . _inputs = UniqList ( ) self . _outputs = UniqList ( ) self . _collect_io ( )


def _on_merge(self, other):
        """
        After merging statements update IO, sensitivity and context

        :attention: rank is not updated
        """
        self._inputs.extend(other._inputs)
        self._outputs.extend(other._outputs)

        if self._sensitivity is not None:
            self._sensitivity.extend(other._sensitivity)
        else:
            assert other._sensitivity is None

        if self._enclosed_for is not None:
            self._enclosed_for.update(other._enclosed_for)
        else:
            assert other._enclosed_for is None

        other_was_top = other.parentStm is None
        if other_was_top:
            other._get_rtl_context().statements.remove(other)
            for s in other._inputs:
                s.endpoints.discard(other)
                s.endpoints.append(self)

            for s in other._outputs:
                s.drivers.discard(other)
                s.drivers.append(self)

def _on_merge ( self , other ) : self . _inputs . extend ( other . _inputs ) self . _outputs . extend ( other . _outputs ) if self . _sensitivity is not None : self . _sensitivity . extend ( other . _sensitivity ) else : assert other . _sensitivity is None if self . _enclosed_for is not None : self . _enclosed_for . update ( other . _enclosed_for ) else : assert other . _enclosed_for is None other_was_top = other . parentStm is None if other_was_top : other . _get_rtl_context ( ) . statements . remove ( other ) for s in other . _inputs : s . endpoints . discard ( other ) s . endpoints . append ( self ) for s in other . _outputs : s . drivers . discard ( other ) s . drivers . append ( self )

After merging statements update IO sensitivity and context


def _is_mergable_statement_list(cls, stmsA, stmsB):
        """
        Walk statements and compare if they can be merged into one statement list
        """
        if stmsA is None and stmsB is None:
            return True

        elif stmsA is None or stmsB is None:
            return False

        a_it = iter(stmsA)
        b_it = iter(stmsB)

        a = _get_stm_with_branches(a_it)
        b = _get_stm_with_branches(b_it)
        while a is not None or b is not None:
            if a is None or b is None or not a._is_mergable(b):
                return False

            a = _get_stm_with_branches(a_it)
            b = _get_stm_with_branches(b_it)

        # lists are empty
        return True

def _is_mergable_statement_list ( cls , stmsA , stmsB ) : if stmsA is None and stmsB is None : return True elif stmsA is None or stmsB is None : return False a_it = iter ( stmsA ) b_it = iter ( stmsB ) a = _get_stm_with_branches ( a_it ) b = _get_stm_with_branches ( b_it ) while a is not None or b is not None : if a is None or b is None or not a . _is_mergable ( b ) : return False a = _get_stm_with_branches ( a_it ) b = _get_stm_with_branches ( b_it ) return True


def _merge_statements(statements: List["HdlStatement"])\
            -> Tuple[List["HdlStatement"], int]:
        """
        Merge statements in list to remove duplicated if-then-else trees

        :return: tuple (list of merged statements, rank decrease due merging)
        :note: rank decrease is sum of ranks of reduced statements
        :attention: statement list has to me mergable
        """
        order = {}
        for i, stm in enumerate(statements):
            order[stm] = i

        new_statements = []
        rank_decrease = 0

        for rank, stms in groupedby(statements, lambda s: s.rank):
            if rank == 0:
                new_statements.extend(stms)
            else:
                if len(stms) == 1:
                    new_statements.extend(stms)
                    continue

                # try to merge statements if they are same condition tree
                for iA, stmA in enumerate(stms):
                    if stmA is None:
                        continue

                    for iB, stmB in enumerate(islice(stms, iA + 1, None)):
                        if stmB is None:
                            continue

                        if stmA._is_mergable(stmB):
                            rank_decrease += stmB.rank
                            stmA._merge_with_other_stm(stmB)
                            stms[iA + 1 + iB] = None
                            new_statements.append(stmA)
                        else:
                            new_statements.append(stmA)
                            new_statements.append(stmB)

        new_statements.sort(key=lambda stm: order[stm])
        return new_statements, rank_decrease

def _merge_statements ( statements : List [ "HdlStatement" ] ) -> Tuple [ List [ "HdlStatement" ] , int ] : order = { } for i , stm in enumerate ( statements ) : order [ stm ] = i new_statements = [ ] rank_decrease = 0 for rank , stms in groupedby ( statements , lambda s : s . rank ) : if rank == 0 : new_statements . extend ( stms ) else : if len ( stms ) == 1 : new_statements . extend ( stms ) continue for iA , stmA in enumerate ( stms ) : if stmA is None : continue for iB , stmB in enumerate ( islice ( stms , iA + 1 , None ) ) : if stmB is None : continue if stmA . _is_mergable ( stmB ) : rank_decrease += stmB . rank stmA . _merge_with_other_stm ( stmB ) stms [ iA + 1 + iB ] = None new_statements . append ( stmA ) else : new_statements . append ( stmA ) new_statements . append ( stmB ) new_statements . sort ( key = lambda stm : order [ stm ] ) return new_statements , rank_decrease

Merge statements in list to remove duplicated if - then - else trees


def _merge_statement_lists(stmsA: List["HdlStatement"], stmsB: List["HdlStatement"])\
            -> List["HdlStatement"]:
        """
        Merge two lists of statements into one

        :return: list of merged statements
        """
        if stmsA is None and stmsB is None:
            return None

        tmp = []

        a_it = iter(stmsA)
        b_it = iter(stmsB)

        a = None
        b = None
        a_empty = False
        b_empty = False

        while not a_empty and not b_empty:
            while not a_empty:
                a = next(a_it, None)
                if a is None:
                    a_empty = True
                    break
                elif a.rank == 0:
                    # simple statement does not require merging
                    tmp.append(a)
                    a = None
                else:
                    break

            while not b_empty:
                b = next(b_it, None)
                if b is None:
                    b_empty = True
                    break
                elif b.rank == 0:
                    # simple statement does not require merging
                    tmp.append(b)
                    b = None
                else:
                    break

            if a is not None or b is not None:
                a._merge_with_other_stm(b)
                tmp.append(a)
                a = None
                b = None

        return tmp

def _merge_statement_lists ( stmsA : List [ "HdlStatement" ] , stmsB : List [ "HdlStatement" ] ) -> List [ "HdlStatement" ] : if stmsA is None and stmsB is None : return None tmp = [ ] a_it = iter ( stmsA ) b_it = iter ( stmsB ) a = None b = None a_empty = False b_empty = False while not a_empty and not b_empty : while not a_empty : a = next ( a_it , None ) if a is None : a_empty = True break elif a . rank == 0 : tmp . append ( a ) a = None else : break while not b_empty : b = next ( b_it , None ) if b is None : b_empty = True break elif b . rank == 0 : tmp . append ( b ) b = None else : break if a is not None or b is not None : a . _merge_with_other_stm ( b ) tmp . append ( a ) a = None b = None return tmp


def _try_reduce_list(statements: List["HdlStatement"]):
        """
        Simplify statements in the list
        """
        io_change = False
        new_statements = []

        for stm in statements:
            reduced, _io_change = stm._try_reduce()
            new_statements.extend(reduced)
            io_change |= _io_change

        new_statements, rank_decrease = HdlStatement._merge_statements(
            new_statements)

        return new_statements, rank_decrease, io_change

def _try_reduce_list ( statements : List [ "HdlStatement" ] ) : io_change = False new_statements = [ ] for stm in statements : reduced , _io_change = stm . _try_reduce ( ) new_statements . extend ( reduced ) io_change |= _io_change new_statements , rank_decrease = HdlStatement . _merge_statements ( new_statements ) return new_statements , rank_decrease , io_change


def _on_parent_event_dependent(self):
        """
        After parrent statement become event dependent
        propagate event dependency flag to child statements
        """
        if not self._is_completly_event_dependent:
            self._is_completly_event_dependent = True
            for stm in self._iter_stms():
                stm._on_parent_event_dependent()

def _on_parent_event_dependent ( self ) : if not self . _is_completly_event_dependent : self . _is_completly_event_dependent = True for stm in self . _iter_stms ( ) : stm . _on_parent_event_dependent ( )


def _set_parent_stm(self, parentStm: "HdlStatement"):
        """
        Assign parent statement and propagate dependency flags if necessary
        """
        was_top = self.parentStm is None
        self.parentStm = parentStm
        if not self._now_is_event_dependent\
                and parentStm._now_is_event_dependent:
            self._on_parent_event_dependent()

        topStatement = parentStm
        while topStatement.parentStm is not None:
            topStatement = topStatement.parentStm

        parent_out_add = topStatement._outputs.append
        parent_in_add = topStatement._inputs.append

        if was_top:
            for inp in self._inputs:
                inp.endpoints.discard(self)
                inp.endpoints.append(topStatement)
                parent_in_add(inp)

            for outp in self._outputs:
                outp.drivers.discard(self)
                outp.drivers.append(topStatement)
                parent_out_add(outp)

            ctx = self._get_rtl_context()
            ctx.statements.discard(self)

        parentStm.rank += self.rank

def _set_parent_stm ( self , parentStm : "HdlStatement" ) : was_top = self . parentStm is None self . parentStm = parentStm if not self . _now_is_event_dependent and parentStm . _now_is_event_dependent : self . _on_parent_event_dependent ( ) topStatement = parentStm while topStatement . parentStm is not None : topStatement = topStatement . parentStm parent_out_add = topStatement . _outputs . append parent_in_add = topStatement . _inputs . append if was_top : for inp in self . _inputs : inp . endpoints . discard ( self ) inp . endpoints . append ( topStatement ) parent_in_add ( inp ) for outp in self . _outputs : outp . drivers . discard ( self ) outp . drivers . append ( topStatement ) parent_out_add ( outp ) ctx = self . _get_rtl_context ( ) ctx . statements . discard ( self ) parentStm . rank += self . rank


def _register_stements(self, statements: List["HdlStatement"],
                           target: List["HdlStatement"]):
        """
        Append statements to this container under conditions specified
        by condSet
        """
        for stm in flatten(statements):
            assert stm.parentStm is None, stm
            stm._set_parent_stm(self)
            target.append(stm)

def _register_stements ( self , statements : List [ "HdlStatement" ] , target : List [ "HdlStatement" ] ) : for stm in flatten ( statements ) : assert stm . parentStm is None , stm stm . _set_parent_stm ( self ) target . append ( stm )


def _destroy(self):
        """
        Disconnect this statement from signals and delete it from RtlNetlist context

        :attention: signal endpoints/drivers will be altered
            that means they can not be used for iteration
        """
        ctx = self._get_rtl_context()
        for i in self._inputs:
            i.endpoints.discard(self)

        for o in self._outputs:
            o.drivers.remove(self)

        ctx.statements.remove(self)

def _destroy ( self ) : ctx = self . _get_rtl_context ( ) for i in self . _inputs : i . endpoints . discard ( self ) for o in self . _outputs : o . drivers . remove ( self ) ctx . statements . remove ( self )


def _reg(self, name, dtype=BIT, defVal=None, clk=None, rst=None):
        """
        Create register in this unit

        :param defVal: default value of this register,
            if this value is specified reset of this component is used
            (unit has to have single interface of class Rst or Rst_n)
        :param clk: optional clok signal specification
        :param rst: optional reset signal specification
        :note: rst/rst_n resolution is done from signal type,
            if it is negated type it is rst_n
        :note: if clk or rst is not specifid default signal
            from parent unit will be used
        """
        if clk is None:
            clk = getClk(self)

        if defVal is None:
            # if no value is specified reset is not required
            rst = None
        else:
            rst = getRst(self)._sig

        if isinstance(dtype, HStruct):
            if defVal is not None:
                raise NotImplementedError()
            container = dtype.fromPy(None)
            for f in dtype.fields:
                if f.name is not None:
                    r = self._reg("%s_%s" % (name, f.name), f.dtype)
                    setattr(container, f.name, r)

            return container

        return self._ctx.sig(name,
                             dtype=dtype,
                             clk=clk._sig,
                             syncRst=rst,
                             defVal=defVal)

def _reg ( self , name , dtype = BIT , defVal = None , clk = None , rst = None ) : if clk is None : clk = getClk ( self ) if defVal is None : rst = None else : rst = getRst ( self ) . _sig if isinstance ( dtype , HStruct ) : if defVal is not None : raise NotImplementedError ( ) container = dtype . fromPy ( None ) for f in dtype . fields : if f . name is not None : r = self . _reg ( "%s_%s" % ( name , f . name ) , f . dtype ) setattr ( container , f . name , r ) return container return self . _ctx . sig ( name , dtype = dtype , clk = clk . _sig , syncRst = rst , defVal = defVal )


def _sig(self, name, dtype=BIT, defVal=None):
        """
        Create signal in this unit
        """
        if isinstance(dtype, HStruct):
            if defVal is not None:
                raise NotImplementedError()
            container = dtype.fromPy(None)
            for f in dtype.fields:
                if f.name is not None:
                    r = self._sig("%s_%s" % (name, f.name), f.dtype)
                    setattr(container, f.name, r)

            return container

        return self._ctx.sig(name, dtype=dtype, defVal=defVal)

def _sig ( self , name , dtype = BIT , defVal = None ) : if isinstance ( dtype , HStruct ) : if defVal is not None : raise NotImplementedError ( ) container = dtype . fromPy ( None ) for f in dtype . fields : if f . name is not None : r = self . _sig ( "%s_%s" % ( name , f . name ) , f . dtype ) setattr ( container , f . name , r ) return container return self . _ctx . sig ( name , dtype = dtype , defVal = defVal )


def _cleanAsSubunit(self):
        """Disconnect internal signals so unit can be reused by parent unit"""
        for pi in self._entity.ports:
            pi.connectInternSig()
        for i in chain(self._interfaces, self._private_interfaces):
            i._clean()

def _cleanAsSubunit ( self ) : for pi in self . _entity . ports : pi . connectInternSig ( ) for i in chain ( self . _interfaces , self . _private_interfaces ) : i . _clean ( )


def walkFlattenFields(sigOrVal, skipPadding=True):
    """
    Walk all simple values in HStruct or HArray
    """
    t = sigOrVal._dtype
    if isinstance(t, Bits):
        yield sigOrVal
    elif isinstance(t, HUnion):
        yield from walkFlattenFields(sigOrVal._val, skipPadding=skipPadding)
    elif isinstance(t, HStruct):
        for f in t.fields:
            isPadding = f.name is None
            if not isPadding or not skipPadding:
                if isPadding:
                    v = f.dtype.fromPy(None)
                else:
                    v = getattr(sigOrVal, f.name)

                yield from walkFlattenFields(v)

    elif isinstance(t, HArray):
        for item in sigOrVal:
            yield from walkFlattenFields(item)
    else:
        raise NotImplementedError(t)

def walkFlattenFields ( sigOrVal , skipPadding = True ) : t = sigOrVal . _dtype if isinstance ( t , Bits ) : yield sigOrVal elif isinstance ( t , HUnion ) : yield from walkFlattenFields ( sigOrVal . _val , skipPadding = skipPadding ) elif isinstance ( t , HStruct ) : for f in t . fields : isPadding = f . name is None if not isPadding or not skipPadding : if isPadding : v = f . dtype . fromPy ( None ) else : v = getattr ( sigOrVal , f . name ) yield from walkFlattenFields ( v ) elif isinstance ( t , HArray ) : for item in sigOrVal : yield from walkFlattenFields ( item ) else : raise NotImplementedError ( t )


def HStruct_unpack(structT, data, getDataFn=None, dataWidth=None):
    """
    opposite of packAxiSFrame
    """
    if getDataFn is None:
        assert dataWidth is not None

        def _getDataFn(x):
            return toHVal(x)._auto_cast(Bits(dataWidth))

        getDataFn = _getDataFn

    val = structT.fromPy(None)

    fData = iter(data)

    # actual is storage variable for items from frameData
    actualOffset = 0
    actual = None

    for v in walkFlattenFields(val, skipPadding=False):
        # walk flatten fields and take values from fData and parse them to
        # field
        required = v._dtype.bit_length()

        if actual is None:
            actualOffset = 0
            try:
                actual = getDataFn(next(fData))
            except StopIteration:
                raise Exception("Input data too short")

            if dataWidth is None:
                dataWidth = actual._dtype.bit_length()
            actuallyHave = dataWidth
        else:
            actuallyHave = actual._dtype.bit_length() - actualOffset

        while actuallyHave < required:
            # collect data for this field
            try:
                d = getDataFn(next(fData))
            except StopIteration:
                raise Exception("Input data too short")

            actual = d._concat(actual)
            actuallyHave += dataWidth

        if actuallyHave >= required:
            # parse value of actual to field
            # skip padding
            _v = actual[(required + actualOffset):actualOffset]
            _v = _v._auto_cast(v._dtype)
            v.val = _v.val
            v.vldMask = _v.vldMask
            v.updateTime = _v.updateTime

            # update slice out what was taken
            actuallyHave -= required
            actualOffset += required

        if actuallyHave == 0:
            actual = None

    if actual is not None:
        assert actual._dtype.bit_length(
        ) - actualOffset < dataWidth, "It should be just a padding at the end of frame"

    return val


def _convSign(self, signed):
        """
        Convert signum, no bit manipulation just data are represented
        differently

        :param signed: if True value will be signed,
            if False value will be unsigned,
            if None value will be vector without any sign specification
        """
        if isinstance(self, Value):
            return self._convSign__val(signed)
        else:
            if self._dtype.signed == signed:
                return self
            t = copy(self._dtype)
            t.signed = signed
            if signed is None:
                cnv = AllOps.BitsAsVec
            elif signed:
                cnv = AllOps.BitsAsSigned
            else:
                cnv = AllOps.BitsAsUnsigned

            return Operator.withRes(cnv, [self], t)

def _convSign ( self , signed ) : if isinstance ( self , Value ) : return self . _convSign__val ( signed ) else : if self . _dtype . signed == signed : return self t = copy ( self . _dtype ) t . signed = signed if signed is None : cnv = AllOps . BitsAsVec elif signed : cnv = AllOps . BitsAsSigned else : cnv = AllOps . BitsAsUnsigned return Operator . withRes ( cnv , [ self ] , t )

Convert signum no bit manipulation just data are represented differently


def sensitivity(proc: HWProcess, *sensitiveTo):
    """
    register sensitivity for process
    """
    for s in sensitiveTo:
        if isinstance(s, tuple):
            sen, s = s
            if sen == SENSITIVITY.ANY:
                s.simSensProcs.add(proc)
            elif sen == SENSITIVITY.RISING:
                s.simRisingSensProcs.add(proc)
            elif sen == SENSITIVITY.FALLING:
                s.simFallingSensProcs.add(proc)
            else:
                raise AssertionError(sen)
        else:
            s.simSensProcs.add(proc)

def sensitivity ( proc : HWProcess , * sensitiveTo ) : for s in sensitiveTo : if isinstance ( s , tuple ) : sen , s = s if sen == SENSITIVITY . ANY : s . simSensProcs . add ( proc ) elif sen == SENSITIVITY . RISING : s . simRisingSensProcs . add ( proc ) elif sen == SENSITIVITY . FALLING : s . simFallingSensProcs . add ( proc ) else : raise AssertionError ( sen ) else : s . simSensProcs . add ( proc )


def simEvalCond(simulator, *conds):
    """
    Evaluate list of values as condition
    """
    _cond = True
    _vld = True
    for v in conds:
        val = bool(v.val)
        fullVld = v.vldMask == 1
        if fullVld:
            if not val:
                return False, True
        else:
            return False, False

        _cond = _cond and val
        _vld = _vld and fullVld

    return _cond, _vld

def simEvalCond ( simulator , * conds ) : _cond = True _vld = True for v in conds : val = bool ( v . val ) fullVld = v . vldMask == 1 if fullVld : if not val : return False , True else : return False , False _cond = _cond and val _vld = _vld and fullVld return _cond , _vld


def connectSimPort(simUnit, subSimUnit, srcName, dstName, direction):
    """
    Connect ports of simulation models by name
    """
    if direction == DIRECTION.OUT:
        origPort = getattr(subSimUnit, srcName)
        newPort = getattr(simUnit, dstName)
        setattr(subSimUnit, srcName, newPort)
    else:
        origPort = getattr(subSimUnit, dstName)
        newPort = getattr(simUnit, srcName)
        setattr(subSimUnit, dstName, newPort)

    subSimUnit._ctx.signals.remove(origPort)

def connectSimPort ( simUnit , subSimUnit , srcName , dstName , direction ) : if direction == DIRECTION . OUT : origPort = getattr ( subSimUnit , srcName ) newPort = getattr ( simUnit , dstName ) setattr ( subSimUnit , srcName , newPort ) else : origPort = getattr ( subSimUnit , dstName ) newPort = getattr ( simUnit , srcName ) setattr ( subSimUnit , dstName , newPort ) subSimUnit . _ctx . signals . remove ( origPort )


def mkUpdater(nextVal: Value, invalidate: bool):
    """
    Create value updater for simulation

    :param nextVal: instance of Value which will be asssiggned to signal
    :param invalidate: flag which tells if value has been compromised
        and if it should be invaidated
    :return: function(value) -> tuple(valueHasChangedFlag, nextVal)
    """

    def updater(currentVal):
        _nextVal = nextVal.clone()
        if invalidate:
            _nextVal.vldMask = 0
        return (valueHasChanged(currentVal, _nextVal), _nextVal)
    return updater

def mkUpdater ( nextVal : Value , invalidate : bool ) : def updater ( currentVal ) : _nextVal = nextVal . clone ( ) if invalidate : _nextVal . vldMask = 0 return ( valueHasChanged ( currentVal , _nextVal ) , _nextVal ) return updater


def mkArrayUpdater(nextItemVal: Value, indexes: Tuple[Value],
                   invalidate: bool):
    """
    Create value updater for simulation for value of array type

    :param nextVal: instance of Value which will be asssiggned to signal
    :param indexes: tuple on indexes where value should be updated
        in target array

    :return: function(value) -> tuple(valueHasChangedFlag, nextVal)
    """
    def updater(currentVal):
        if len(indexes) > 1:
            raise NotImplementedError("[TODO] implement for more indexes")

        _nextItemVal = nextItemVal.clone()
        if invalidate:
            _nextItemVal.vldMask = 0

        index = indexes[0]
        change = valueHasChanged(currentVal._getitem__val(index), _nextItemVal)
        currentVal._setitem__val(index, _nextItemVal)
        return (change, currentVal)

    return updater

def
mkArrayUpdater
(
nextItemVal
:
Value
,
indexes
:
Tuple
[
Value
]
,
invalidate
:
bool
)
:
def
updater
(
currentVal
)
:
if
len
(
indexes
)
>
1
:
raise
NotImplementedError
(
"[TODO] implement for more indexes"
)
_nextItemVal
=
nextItemVal
.
clone
(
)
if
invalidate
:
_nextItemVal
.
vldMask
=
0
index
=
indexes
[
0
]
change
=
valueHasChanged
(
currentVal
.
_getitem__val
(
index
)
,
_nextItemVal
)
currentVal
.
_setitem__val
(
index
,
_nextItemVal
)
return
(
change
,
currentVal
)
return
updater


def vec(val, width, signed=None):
    """create hdl vector value"""
    return Bits(width, signed, forceVector=True).fromPy(val)

def vec ( val , width , signed = None ) : return Bits ( width , signed , forceVector = True ) . fromPy ( val )


def HWProcess(cls, proc: HWProcess, ctx: ResourceContext) -> None:
        """
        Gues resource usage by HWProcess
        """
        seen = ctx.seen
        for stm in proc.statements:
            encl = stm._enclosed_for
            full_ev_dep = stm._is_completly_event_dependent
            now_ev_dep = stm._now_is_event_dependent
            ev_dep = full_ev_dep or now_ev_dep

            out_mux_dim = count_mux_inputs_for_outputs(stm)
            for o in stm._outputs:
                if o in seen:
                    continue

                i = out_mux_dim[o]
                if isinstance(o._dtype, HArray):
                    assert i == 1, (o, i, " only one ram port per HWProcess")
                    for a in walk_assignments(stm, o):
                        assert len(a.indexes) == 1, "one address per RAM port"
                        addr = a.indexes[0]
                    ctx.registerRAM_write_port(o, addr, ev_dep)
                elif ev_dep:
                    ctx.registerFF(o)
                    if i > 1:
                        ctx.registerMUX(stm, o, i)
                elif o not in encl:
                    ctx.registerLatch(o)
                    if i > 1:
                        ctx.registerMUX(stm, o, i)
                elif i > 1:
                    ctx.registerMUX(stm, o, i)
                else:
                    # just a connection
                    continue

            if isinstance(stm, SwitchContainer):
                caseEqs = set([stm.switchOn._eq(c[0]) for c in stm.cases])
                inputs = chain(
                    [sig for sig in stm._inputs if sig not in caseEqs], [stm.switchOn])
            else:
                inputs = stm._inputs

            for i in inputs:
                # discover only internal signals in this statements for
                # operators
                if not i.hidden or i in seen:
                    continue

                cls.HWProcess_operators(i, ctx, ev_dep)

def
HWProcess
(
cls
,
proc
:
HWProcess
,
ctx
:
ResourceContext
)
->
:
seen
=
ctx
.
seen
for
stm
in
proc
.
statements
:
encl
=
stm
.
_enclosed_for
full_ev_dep
=
stm
.
_is_completly_event_dependent
now_ev_dep
=
stm
.
_now_is_event_dependent
ev_dep
=
full_ev_dep
or
now_ev_dep
out_mux_dim
=
count_mux_inputs_for_outputs
(
stm
)
for
o
in
stm
.
_outputs
:
if
o
in
seen
:
continue
i
=
out_mux_dim
[
o
]
if
isinstance
(
o
.
_dtype
,
HArray
)
:
assert
i
==
1
,
(
o
,
i
,
" only one ram port per HWProcess"
)
for
a
in
walk_assignments
(
stm
,
o
)
:
assert
len
(
a
.
indexes
)
==
1
,
"one address per RAM port"
addr
=
a
.
indexes
[
0
]
ctx
.
registerRAM_write_port
(
o
,
addr
,
ev_dep
)
elif
ev_dep
:
ctx
.
registerFF
(
o
)
if
i
>
1
:
ctx
.
registerMUX
(
stm
,
o
,
i
)
elif
o
not
in
encl
:
ctx
.
registerLatch
(
o
)
if
i
>
1
:
ctx
.
registerMUX
(
stm
,
o
,
i
)
elif
i
>
1
:
ctx
.
registerMUX
(
stm
,
o
,
i
)
else
:
continue
if
isinstance
(
stm
,
SwitchContainer
)
:
caseEqs
=
set
(
[
stm
.
switchOn
.
_eq
(
c
[
0
]
)
for
c
in
stm
.
cases
]
)
inputs
=
chain
(
[
sig
for
sig
in
stm
.
_inputs
if
sig
not
in
caseEqs
]
,
[
stm
.
switchOn
]
)
else
:
inputs
=
stm
.
_inputs
for
i
in
inputs
:
if
not
i
.
hidden
or
i
in
seen
:
continue
cls
.
HWProcess_operators
(
i
,
ctx
,
ev_dep
)


def evalParam(p):
    """
    Get value of parameter
    """
    while isinstance(p, Param):
        p = p.get()

    if isinstance(p, RtlSignalBase):
        return p.staticEval()
        # use rather param inheritance instead of param as param value
    return toHVal(p)

def evalParam ( p ) : while isinstance ( p , Param ) : p = p . get ( ) if isinstance ( p , RtlSignalBase ) : return p . staticEval ( ) return toHVal ( p )


def set(self, val):
        """
        set value of this param
        """
        assert not self.__isReadOnly, \
            ("This parameter(%s) was locked"
             " and now it can not be changed" % self.name)
        assert self.replacedWith is None, \
            ("This param was replaced with new one and this "
             "should not exists")

        val = toHVal(val)
        self.defVal = val
        self._val = val.staticEval()
        self._dtype = self._val._dtype


def HTypeFromIntfMap(interfaceMap):
    """
    Generate flattened register map for HStruct

    :param interfaceMap: sequence of
        tuple (type, name) or (will create standard struct field member)
        interface or (will create a struct field from interface)
        instance of hdl type (is used as padding)
        tuple (list of interface, name)
    :param DATA_WIDTH: width of word
    :param terminalNodes: None or set whre are placed StructField instances
        which are derived directly from interface
    :return: generator of tuple (type, name, BusFieldInfo)
    """
    structFields = []

    for m in interfaceMap:
        f = HTypeFromIntfMapItem(m)
        structFields.append(f)

    return HStruct(*structFields)

def HTypeFromIntfMap ( interfaceMap ) : structFields = [ ] for m in interfaceMap : f = HTypeFromIntfMapItem ( m ) structFields . append ( f ) return HStruct ( * structFields )


def finalize(self):
        """
        Resolve ports of discovered memories
        """
        ff_to_remove = 0
        res = self.resources
        for m, addrDict in self.memories.items():
            rwSyncPorts, rSyncPorts, wSyncPorts = 0, 0, 0
            rwAsyncPorts, rAsyncPorts, wAsyncPorts = 0, 0, 0
            rSync_wAsyncPorts, rAsync_wSyncPorts = 0, 0

            for _, (rSync, wSync, rAsync, wAsync) in addrDict.items():
                if rSync:
                    ff_to_remove += rSync * m._dtype.elmType.bit_length()

                # resolve port count for this addr signal
                rwSync = min(rSync, wSync)
                rSync -= rwSync
                wSync -= rwSync

                rwAsync = min(rAsync, wAsync)
                rAsync -= rwAsync
                wAsync -= rwAsync

                rSync_wAsync = min(rSync, wAsync)
                rSync -= rSync_wAsync
                wAsync -= rSync_wAsync

                rAsync_wSync = min(rAsync, wSync)
                rAsync -= rAsync_wSync
                wSync -= rAsync_wSync

                # update port counts for mem
                rwSyncPorts += rwSync
                rSyncPorts += rSync
                wSyncPorts += wSync
                rwAsyncPorts += rwAsync
                rAsyncPorts += rAsync
                wAsyncPorts += wAsync

                rSync_wAsyncPorts += rSync_wAsync
                rAsync_wSyncPorts += rAsync_wSync
            k = ResourceRAM(m._dtype.elmType.bit_length(),
                            int(m._dtype.size),
                            rwSyncPorts, rSyncPorts, wSyncPorts,
                            rSync_wAsyncPorts,
                            rwAsyncPorts, rAsyncPorts, wAsyncPorts,
                            rAsync_wSyncPorts)
            res[k] = res.get(k, 0) + 1

        self.memories.clear()

        # remove register on read ports which will be merged into ram
        if ff_to_remove:
            ff_cnt = res[ResourceFF]
            ff_cnt -= ff_to_remove
            if ff_cnt:
                res[ResourceFF] = ff_cnt
            else:
                del res[ResourceFF]

def finalize ( self ) : ff_to_remove = 0 res = self . resources for m , addrDict in self . memories . items ( ) : rwSyncPorts , rSyncPorts , wSyncPorts = 0 , 0 , 0 rwAsyncPorts , rAsyncPorts , wAsyncPorts = 0 , 0 , 0 rSync_wAsyncPorts , rAsync_wSyncPorts = 0 , 0 for _ , ( rSync , wSync , rAsync , wAsync ) in addrDict . items ( ) : if rSync : ff_to_remove += rSync * m . _dtype . elmType . bit_length ( ) rwSync = min ( rSync , wSync ) rSync -= rwSync wSync -= rwSync rwAsync = min ( rAsync , wAsync ) rAsync -= rwAsync wAsync -= rwAsync rSync_wAsync = min ( rSync , wAsync ) rSync -= rSync_wAsync wAsync -= rSync_wAsync rAsync_wSync = min ( rAsync , wSync ) rAsync -= rAsync_wSync wSync -= rAsync_wSync rwSyncPorts += rwSync rSyncPorts += rSync wSyncPorts += wSync rwAsyncPorts += rwAsync rAsyncPorts += rAsync wAsyncPorts += wAsync rSync_wAsyncPorts += rSync_wAsync rAsync_wSyncPorts += rAsync_wSync k = ResourceRAM ( m . _dtype . elmType . bit_length ( ) , int ( m . _dtype . size ) , rwSyncPorts , rSyncPorts , wSyncPorts , rSync_wAsyncPorts , rwAsyncPorts , rAsyncPorts , wAsyncPorts , rAsync_wSyncPorts ) res [ k ] = res . get ( k , 0 ) + 1 self . memories . clear ( ) if ff_to_remove : ff_cnt = res [ ResourceFF ] ff_cnt -= ff_to_remove if ff_cnt : res [ ResourceFF ] = ff_cnt else : del res [ ResourceFF ]


def _getIndexCascade(self):
        """
        Find out if this signal is something indexed
        """
        try:
            # now I am result of the index  xxx[xx] <= source
            # get index op
            d = self.singleDriver()
            try:
                op = d.operator
            except AttributeError:
                return

            if op == AllOps.INDEX:
                # get signal on which is index applied
                indexedOn = d.operands[0]
                if isinstance(indexedOn, RtlSignalBase):
                    # [TODO] multidimensional indexing
                    return indexedOn, [d.operands[1]]
                else:
                    raise Exception(
                        "can not drive static value %r" % indexedOn)

        except (MultipleDriversErr, NoDriverErr):
            pass

def
_getIndexCascade
(
self
)
:
try
:
d
=
self
.
singleDriver
(
)
try
:
op
=
d
.
operator
except
AttributeError
:
return
if
op
==
AllOps
.
INDEX
:
indexedOn
=
d
.
operands
[
0
]
if
isinstance
(
indexedOn
,
RtlSignalBase
)
:
return
indexedOn
,
[
d
.
operands
[
1
]
]
else
:
raise
Exception
(
"can not drive static value %r"
%
indexedOn
)
except
(
MultipleDriversErr
,
NoDriverErr
)
:
pass