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 Architecture(cls, arch: Architecture, ctx): with CurrentUnitSwap(ctx, arch.entity.origin): variables = [] procs = [] extraTypes = set() extraTypes_serialized = [] arch.variables.sort(key=lambda x: (x.name, x._instId)) arch.processes.sort(key=lambda x: (x.name, maxStmId(x))) arch.components.sort(key=lambda x: x.name) arch.componentInstances.sort(key=lambda x: x._name) childCtx = ctx.withIndent() for v in arch.variables: t = v._dtype # if type requires extra definition if isinstance(t, (HEnum, HArray)) and t not in extraTypes: extraTypes.add(v._dtype) extraTypes_serialized.append( cls.HdlType(t, childCtx, declaration=True)) v.name = ctx.scope.checkedName(v.name, v) serializedVar = cls.SignalItem(v, childCtx, declaration=True) variables.append(serializedVar) for p in arch.processes: procs.append(cls.HWProcess(p, childCtx)) # architecture names can be same for different entities # arch.name = scope.checkedName(arch.name, arch, isGlobal=True) uniqComponents = list( map(lambda x: x[1][0], groupedby(arch.components, lambda c: c.name))) uniqComponents.sort(key=lambda c: c.name) components = list( map(lambda c: cls.Component(c, childCtx), uniqComponents)) componentInstances = list( map(lambda c: cls.ComponentInstance(c, childCtx), arch.componentInstances)) return cls.architectureTmpl.render( indent=getIndent(ctx.indent), entityName=arch.getEntityName(), name=arch.name, variables=variables, extraTypes=extraTypes_serialized, processes=procs, components=components, componentInstances=componentInstances)
def Architecture(cls, arch, scope): variables = [] procs = [] extraTypes = set() extraTypes_serialized = [] arch.variables.sort(key=lambda x: x.name) arch.processes.sort(key=lambda x: (x.name, maxStmId(x))) arch.components.sort(key=lambda x: x.name) arch.componentInstances.sort(key=lambda x: x._name) def createTmpVarFn(suggestedName, dtype): raise NotImplementedError() for v in arch.variables: t = v._dtype # if type requires extra definition if isinstance(t, (Enum, Array)) and t not in extraTypes: extraTypes.add(v._dtype) extraTypes_serialized.append( cls.HdlType(t, createTmpVarFn, scope, declaration=True)) v.name = scope.checkedName(v.name, v) serializedVar = cls.SignalItem(v, createTmpVarFn, declaration=True) variables.append(serializedVar) for p in arch.processes: procs.append(cls.HWProcess(p, scope)) # architecture names can be same for different entities # arch.name = scope.checkedName(arch.name, arch, isGlobal=True) uniqComponents = list( map(lambda x: x[1][0], groupedby(arch.components, lambda c: c.name))) uniqComponents.sort(key=lambda c: c.name) components = list( map(lambda c: cls.Component(c, createTmpVarFn), uniqComponents)) componentInstances = list( map(lambda c: cls.ComponentInstance(c, createTmpVarFn, scope), arch.componentInstances)) return architectureTmpl.render({ "entityName": arch.getEntityName(), "name": arch.name, "variables": variables, "extraTypes": extraTypes_serialized, "processes": procs, "components": components, "componentInstances": componentInstances })
def buildProcessesOutOfAssignments(self): """ Render conditional assignments to statements and wrap them with process statement """ assigments = where(self.startsOfDataPaths, lambda x: isinstance(x, Assignment)) for sig, dps in groupedby(assigments, lambda x: x.dst): dps = list(dps) name = "" if not sig.hasGenericName: name = sig.name sig.hidden = False haveNotIndexes = True for dp in dps: haveNotIndexes = haveNotIndexes and not dp.indexes # render sequential statements in process # (conversion from netlist to statements) hasCombDriver = False for stm in renderIfTree(dps): p = HWProcess("assig_process_" + name) if sig._useNopVal and not isEnclosed(stm): n = sig._nopVal p.statements.append(Assignment(n, sig)) if isinstance(n, RtlSignal): p.sensitivityList.add(n) p.statements.append(stm) sensitivity = discoverSensitivity(stm) p.sensitivityList.update(sensitivity) isEventDependent = False for s in p.sensitivityList: if isinstance(s, Operator): # event operator s.ops[0].hidden = False isEventDependent = True else: s.hidden = False if hasCombDriver and not isEventDependent and haveNotIndexes: raise MultipleDriversExc( "%s: Signal %s has multiple combinational drivers" % (self.getDebugScopeName(), name)) hasCombDriver = hasCombDriver or not isEventDependent yield p
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 as_hdl_HdlModuleDef(self, o: HdlModuleDef): """ Translate hwt types and expressions to HDL AST and add explicit components """ _o = super(ToHdlAstVhdl2008, self).as_hdl_HdlModuleDef(o) component_insts = [] for c in _o.objs: component_insts.extend(self._find_HdlCompInst(c)) # select comonent instances whith an unique module_name components = [ x[1][0] for x in groupedby(component_insts, lambda c: c.module_name) ] components.sort(key=lambda c: c.module_name) components = [self.as_hdl_HldComponent(c) for c in components] if components: _o.objs = components + _o.objs res = HdlContext() res.objs.extend(self.DEFAULT_IMPORTS) res.objs.append(_o) return res
def readPart(self, awAddr, w_hs): ADDR_STEP = self._getAddrStep() DW = int(self.DATA_WIDTH) # build read data output mux r = self.bus.r ar = self.bus.ar rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData']) isBramAddr = self._sig("isBramAddr") rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\ .Trans(rSt_t.rdIdle, (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData), (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd) ).Trans(rSt_t.bramRd, (~w_hs, rSt_t.rdData) ).Trans(rSt_t.rdData, (r.ready, rSt_t.rdIdle) ).stateReg arRd = rSt._eq(rSt_t.rdIdle) ar.ready(arRd & ~w_hs) # save ar addr arAddr = self._reg('arAddr', ar.addr._dtype) If(ar.valid & arRd, arAddr(ar.addr)) isInAddrRange = self.isInMyAddrRange(arAddr) r.valid(rSt._eq(rSt_t.rdData)) If(isInAddrRange, r.resp(RESP_OKAY)).Else(r.resp(RESP_SLVERR)) if self._bramPortMapped: rdataReg = self._reg("rdataReg", r.data._dtype) _isInBramFlags = [] # list of tuples (cond, rdataReg assignment) rregCases = [] # index of bram from where we reads from bramRdIndx = self._reg("bramRdIndx", Bits(log2ceil(len(self._bramPortMapped)))) bramRdIndxSwitch = Switch(bramRdIndx) for bramIndex, t in enumerate(self._bramPortMapped): port = self.getPort(t) # map addr for bram ports dstAddrStep = port.dout._dtype.bit_length() (_isMyArAddr, arAddrConnect) = self.propagateAddr(ar.addr, ADDR_STEP, port.addr, dstAddrStep, t) (_, ar2AddrConnect) = self.propagateAddr(arAddr, ADDR_STEP, port.addr, dstAddrStep, t) (_isMyAwAddr, awAddrConnect) = self.propagateAddr(awAddr, ADDR_STEP, port.addr, dstAddrStep, t) prioritizeWrite = _isMyAwAddr & w_hs If(prioritizeWrite, awAddrConnect).Elif(rSt._eq(rSt_t.rdIdle), arAddrConnect).Else(ar2AddrConnect) _isInBramFlags.append(_isMyArAddr) port.en((_isMyArAddr & ar.valid) | prioritizeWrite) port.we(prioritizeWrite) rregCases.append((_isMyArAddr, bramRdIndx(bramIndex))) bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout)) bramRdIndxSwitch.Default(rdataReg(rdataReg)) If(arRd, SwitchLogic(rregCases)) isBramAddr(Or(*_isInBramFlags)) else: rdataReg = None isBramAddr(0) directlyMappedWors = [] for w, items in sorted(groupedby( self._directlyMapped, lambda t: t.bitAddr // DW * (DW // ADDR_STEP)), key=lambda x: x[0]): lastBit = 0 res = [] items.sort(key=lambda t: t.bitAddr) for t in items: b = t.bitAddr % DW if b > lastBit: # add padding pad_w = b - lastBit pad = Bits(pad_w).fromPy(None) res.append(pad) lastBit += pad_w din = self.getPort(t).din res.append(din) lastBit += din._dtype.bit_length() if lastBit != DW: # add at end padding pad = Bits(DW - lastBit).fromPy(None) res.append(pad) directlyMappedWors.append((w, Concat(*reversed(res)))) Switch(arAddr).addCases([ (w[0], r.data(w[1])) for w in directlyMappedWors ]).Default(r.data(rdataReg))
def readPart(self, awAddr, w_hs): ADDR_STEP = self._getAddrStep() DW = int(self.DATA_WIDTH) # build read data output mux r = self.bus.r ar = self.bus.ar rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData']) isBramAddr = self._sig("isBramAddr") rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\ .Trans(rSt_t.rdIdle, (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData), (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd) ).Trans(rSt_t.bramRd, (~w_hs, rSt_t.rdData) ).Trans(rSt_t.rdData, (r.ready, rSt_t.rdIdle) ).stateReg arRd = rSt._eq(rSt_t.rdIdle) ar.ready(arRd & ~w_hs) # save ar addr arAddr = self._reg('arAddr', ar.addr._dtype) If(ar.valid & arRd, arAddr(ar.addr) ) isInAddrRange = self.isInMyAddrRange(arAddr) r.valid(rSt._eq(rSt_t.rdData)) If(isInAddrRange, r.resp(RESP_OKAY) ).Else( r.resp(RESP_SLVERR) ) if self._bramPortMapped: rdataReg = self._reg("rdataReg", r.data._dtype) _isInBramFlags = [] # list of tuples (cond, rdataReg assignment) rregCases = [] # index of bram from where we reads from bramRdIndx = self._reg("bramRdIndx", Bits( log2ceil(len(self._bramPortMapped)))) bramRdIndxSwitch = Switch(bramRdIndx) for bramIndex, t in enumerate(self._bramPortMapped): port = self.getPort(t) # map addr for bram ports dstAddrStep = port.dout._dtype.bit_length() (_isMyArAddr, arAddrConnect) = self.propagateAddr( ar.addr, ADDR_STEP, port.addr, dstAddrStep, t) (_, ar2AddrConnect) = self.propagateAddr( arAddr, ADDR_STEP, port.addr, dstAddrStep, t) (_isMyAwAddr, awAddrConnect) = self.propagateAddr( awAddr, ADDR_STEP, port.addr, dstAddrStep, t) prioritizeWrite = _isMyAwAddr & w_hs If(prioritizeWrite, awAddrConnect ).Elif(rSt._eq(rSt_t.rdIdle), arAddrConnect ).Else( ar2AddrConnect ) _isInBramFlags.append(_isMyArAddr) port.en((_isMyArAddr & ar.valid) | prioritizeWrite) port.we(prioritizeWrite) rregCases.append((_isMyArAddr, bramRdIndx(bramIndex))) bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout)) bramRdIndxSwitch.Default(rdataReg(rdataReg)) If(arRd, SwitchLogic(rregCases) ) isBramAddr(Or(*_isInBramFlags)) else: rdataReg = None isBramAddr(0) directlyMappedWors = [] for w, items in sorted(groupedby(self._directlyMapped, lambda t: t.bitAddr // DW * (DW // ADDR_STEP)), key=lambda x: x[0]): lastBit = 0 res = [] items.sort(key=lambda t: t.bitAddr) for t in items: b = t.bitAddr % DW if b > lastBit: # add padding pad_w = b - lastBit pad = Bits(pad_w).fromPy(None) res.append(pad) lastBit += pad_w din = self.getPort(t).din res.append(din) lastBit += din._dtype.bit_length() if lastBit != DW: # add at end padding pad = Bits(DW - lastBit).fromPy(None) res.append(pad) directlyMappedWors.append((w, Concat(*reversed(res)))) Switch(arAddr).addCases( [(w[0], r.data(w[1])) for w in directlyMappedWors] ).Default( r.data(rdataReg) )