def _parseTemplate(self): self.WORD_ADDR_STEP = self._getWordAddrStep() self.ADDR_STEP = self._getAddrStep() AW = int(self.ADDR_WIDTH) SUGGESTED_AW = self._suggestedAddrWidth() assert SUGGESTED_AW <= AW, ("Address width too small", SUGGESTED_AW, AW) tmpl = TransTmpl(self.STRUCT_TEMPLATE) self._ADDR_MIN = TransTmpl_get_min_addr(tmpl) // self.ADDR_STEP self._ADDR_MAX = ceil(TransTmpl_get_max_addr(tmpl) / self.ADDR_STEP) # resolve addresses for bram port mapped fields self._bramPortMapped = [] def shouldEnterFn(trans_tmpl: TransTmpl): p = trans_tmpl.getFieldPath() intf = self.decoded._fieldsToInterfaces[p] if isinstance(intf, (StructIntf, UnionSink, UnionSource, HObjList)): shouldEnter = True shouldUse = False elif isinstance(intf, BramPort_withoutClk): shouldEnter = False shouldUse = True else: shouldEnter = False shouldUse = False return shouldEnter, shouldUse for ((base, end), t) in tmpl.walkFlatten(shouldEnterFn=shouldEnterFn): self._bramPortMapped.append(((base, end), t)) # resolve exact addresses for directly mapped field parts directly_mapped_fields = {} for p, out in self.decoded._fieldsToInterfaces.items(): if not isinstance(out, (RegCntrl, Signal)): continue a = directly_mapped_fields for _p in p: if isinstance(_p, int) and _p != 0: # we need spec only for first array item break a = a.setdefault(_p, {}) dmw = self._directly_mapped_words = [] if directly_mapped_fields: DW = self.DATA_WIDTH directly_mapped_t = HdlType_select(self.STRUCT_TEMPLATE, directly_mapped_fields) tmpl = TransTmpl(directly_mapped_t) frames = list( FrameTmpl.framesFromTransTmpl( tmpl, DW, maxPaddingWords=0, trimPaddingWordsOnStart=True, trimPaddingWordsOnEnd=True, )) for f in frames: f_word_offset = f.startBitAddr // DW for (w_i, items) in f.walkWords(showPadding=True): dmw.append((w_i + f_word_offset, items))
class StructReader(AxiS_frameParser): """ This unit downloads required structure fields over rDatapump interface from address specified by get interface :ivar MAX_DUMMY_WORDS: Param, specifies maximum dummy bus words between fields if there is more of ignored space transaction will be split to :ivar ID: Param, id for transactions on bus :ivar READ_ACK: Param, if true ready on "get" will be set only when component is in idle (if false "get" is regular handshaked interface) :ivar SHARED_READY: Param, if this is true field interfaces will be of type VldSynced and single ready signal will be used for all else every interface will be instance of Handshaked and it will have it's own ready(rd) signal :attention: interfaces of field will not send data in same time .. aafig:: get (base addr) +---------+ +---------------- +------> field0 | | | +---------+ bus req +--v---+-+ <------------+ | +---------+ | reader +----> field1 | +------------> | +---------+ bus data +-------+-+ | +---------+ +------> field2 | +---------+ :note: names in the picture are just illustrative .. hwt-schematic:: _example_StructReader """ def __init__(self, structT, tmpl=None, frames=None): """ :param structT: instance of HStruct which specifies data format to download :param tmpl: instance of TransTmpl for this structT :param frames: list of FrameTmpl instances for this tmpl :note: if tmpl and frames are None they are resolved from structT parseTemplate :note: this unit can parse sequence of frames, if they are specified by "frames" :attention: interfaces for each field in struct will be dynamically created :attention: structT can not contain fields with variable size like HStream """ Unit.__init__(self) assert isinstance(structT, HStruct) self._structT = structT if tmpl is not None: assert frames is not None, "tmpl and frames can be used only together" else: assert frames is None, "tmpl and frames can be used only together" self._tmpl = tmpl self._frames = frames def _config(self): self.ID = Param(0) AxiRDatapumpIntf._config(self) self.USE_STRB.set(False) self.READ_ACK = Param(False) self.SHARED_READY = Param(False) def maxWordIndex(self): return max(map(lambda f: f.endBitAddr - 1, self._frames)) // int(self.DATA_WIDTH) def parseTemplate(self): if self._tmpl is None: self._tmpl = TransTmpl(self._structT) if self._frames is None: DW = int(self.DATA_WIDTH) frames = FrameTmpl.framesFromTransTmpl( self._tmpl, DW, trimPaddingWordsOnStart=True, trimPaddingWordsOnEnd=True) self._frames = list(frames) def _declr(self): addClkRstn(self) self.dataOut = StructIntf(self._structT, self._mkFieldIntf)._m() g = self.get = Handshaked() # data signal is addr of structure to download g._replaceParam(g.DATA_WIDTH, self.ADDR_WIDTH) self.parseTemplate() with self._paramsShared(): # interface for communication with datapump self.rDatapump = AxiRDatapumpIntf()._m() self.rDatapump.MAX_LEN.set(self.maxWordIndex() + 1) with self._paramsShared(exclude={self.ID_WIDTH}): self.parser = AxiS_frameParser(self._structT, tmpl=self._tmpl, frames=self._frames) self.parser.SYNCHRONIZE_BY_LAST.set(False) if self.SHARED_READY: self.ready = Signal() def _impl(self): propagateClkRstn(self) req = self.rDatapump.req req.rem(0) if self.READ_ACK: get = self.get else: get = HsBuilder(self, self.get).buff().end def f(frame, indx): s = [req.addr(get.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), req.vld(get.vld) ] isLastFrame = indx == len(self._frames) - 1 if isLastFrame: rd = req.rd else: rd = 0 s.append(get.rd(rd)) ack = StreamNode(masters=[get], slaves=[self.rDatapump.req]).ack() return s, ack StaticForEach(self, self._frames, f) r = self.rDatapump.r data_sig_to_exclude = [] req.id(self.ID) if hasattr(r, "id"): data_sig_to_exclude.append(r.id) if hasattr(r, "strb"): data_sig_to_exclude.append(r.strb) connect(r, self.parser.dataIn, exclude=data_sig_to_exclude) for _, field in self._tmpl.walkFlatten(): myIntf = self.dataOut._fieldsToInterfaces[field.origin] parserIntf = self.parser.dataOut._fieldsToInterfaces[field.origin] myIntf(parserIntf)
class StructReader(AxiS_frameParser): """ This unit downloads required structure fields over rDatapump interface from address specified by get interface :ivar MAX_DUMMY_WORDS: Param, specifies maximum dummy bus words between fields if there is more of ignored space transaction will be split to :ivar ID: Param, id for transactions on bus :ivar READ_ACK: Param, if true ready on "get" will be set only when component is in idle (if false "get" is regular handshaked interface) :ivar SHARED_READY: Param, if this is true field interfaces will be of type VldSynced and single ready signal will be used for all else every interface will be instance of Handshaked and it will have it's own ready(rd) signal :attention: interfaces of field will not send data in same time .. aafig:: get (base addr) +---------+ +---------------- +------> field0 | | | +---------+ bus req +--v---+-+ <------------+ | +---------+ | reader +----> field1 | +------------> | +---------+ bus data +-------+-+ | +---------+ +------> field2 | +---------+ :note: names in the picture are just illustrative .. hwt-schematic:: _example_StructReader """ def __init__(self, structT, tmpl=None, frames=None): """ :param structT: instance of HStruct which specifies data format to download :param tmpl: instance of TransTmpl for this structT :param frames: list of FrameTmpl instances for this tmpl :note: if tmpl and frames are None they are resolved from structT parseTemplate :note: this unit can parse sequence of frames, if they are specified by "frames" :attention: interfaces for each field in struct will be dynamically created :attention: structT can not contain fields with variable size like HStream """ Unit.__init__(self) assert isinstance(structT, HStruct) self._structT = structT if tmpl is not None: assert frames is not None, "tmpl and frames can be used only together" else: assert frames is None, "tmpl and frames can be used only together" self._tmpl = tmpl self._frames = frames def _config(self): self.ID = Param(0) AxiRDatapumpIntf._config(self) self.USE_STRB.set(False) self.READ_ACK = Param(False) self.SHARED_READY = Param(False) def maxWordIndex(self): return max(map(lambda f: f.endBitAddr - 1, self._frames)) // int( self.DATA_WIDTH) def parseTemplate(self): if self._tmpl is None: self._tmpl = TransTmpl(self._structT) if self._frames is None: DW = int(self.DATA_WIDTH) frames = FrameTmpl.framesFromTransTmpl( self._tmpl, DW, trimPaddingWordsOnStart=True, trimPaddingWordsOnEnd=True) self._frames = list(frames) def _declr(self): addClkRstn(self) self.dataOut = StructIntf(self._structT, self._mkFieldIntf)._m() g = self.get = Handshaked( ) # data signal is addr of structure to download g._replaceParam(g.DATA_WIDTH, self.ADDR_WIDTH) self.parseTemplate() with self._paramsShared(): # interface for communication with datapump self.rDatapump = AxiRDatapumpIntf()._m() self.rDatapump.MAX_LEN.set(self.maxWordIndex() + 1) with self._paramsShared(exclude={self.ID_WIDTH}): self.parser = AxiS_frameParser(self._structT, tmpl=self._tmpl, frames=self._frames) self.parser.SYNCHRONIZE_BY_LAST.set(False) if self.SHARED_READY: self.ready = Signal() def _impl(self): propagateClkRstn(self) req = self.rDatapump.req req.rem(0) if self.READ_ACK: get = self.get else: get = HsBuilder(self, self.get).buff().end def f(frame, indx): s = [ req.addr(get.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), req.vld(get.vld) ] isLastFrame = indx == len(self._frames) - 1 if isLastFrame: rd = req.rd else: rd = 0 s.append(get.rd(rd)) ack = StreamNode(masters=[get], slaves=[self.rDatapump.req]).ack() return s, ack StaticForEach(self, self._frames, f) r = self.rDatapump.r data_sig_to_exclude = [] req.id(self.ID) if hasattr(r, "id"): data_sig_to_exclude.append(r.id) if hasattr(r, "strb"): data_sig_to_exclude.append(r.strb) connect(r, self.parser.dataIn, exclude=data_sig_to_exclude) for _, field in self._tmpl.walkFlatten(): myIntf = self.dataOut._fieldsToInterfaces[field.origin] parserIntf = self.parser.dataOut._fieldsToInterfaces[field.origin] myIntf(parserIntf)
class StructReader(AxiS_frameParser): """ This unit downloads required structure fields over rDatapump interface from address specified by get interface :ivar ~.ID: Param, id for transactions on bus :ivar ~.READ_ACK: Param, if true ready on "get" will be set only when component is in idle (if false "get" is regular handshaked interface) :ivar ~.SHARED_READY: Param, if this is true field interfaces will be of type VldSynced and single ready signal will be used for all else every interface will be instance of Handshaked and it will have it's own ready(rd) signal :attention: interfaces of field will not send data in same time .. aafig:: get (base addr) +---------+ +---------------- +------>| field0 | | | +---------+ v | bus req +------+--+ <------------+ | +---------+ | reader +--->| field1 | +----------->| | +---------+ bus data +-------+-+ | +---------+ +----->| field2 | +---------+ :note: names in the picture are just illustrative .. hwt-autodoc:: _example_StructReader """ def __init__(self, structT, tmpl=None, frames=None): """ :param structT: instance of HStruct which specifies data format to download :param tmpl: instance of TransTmpl for this structT :param frames: list of FrameTmpl instances for this tmpl :note: if tmpl and frames are None they are resolved from structT parseTemplate :note: this unit can parse sequence of frames, if they are specified by "frames" :attention: interfaces for each field in struct will be dynamically created :attention: structT can not contain fields with variable size like HStream """ Unit.__init__(self) assert isinstance(structT, HStruct) TemplateConfigured.__init__(self, structT, tmpl=tmpl, frames=frames) def _config(self): self.ID = Param(0) AxiRDatapumpIntf._config(self) self.USE_STRB = False self.READ_ACK = Param(False) self.SHARED_READY = Param(False) def maxWordIndex(self): return max(f.endBitAddr - 1 for f in self._frames) // self.DATA_WIDTH def maxBytesInTransaction(self): return ceil(max( [f.parts[-1].endOfPart - f.startBitAddr for f in self._frames] ) / 8) def parseTemplate(self): if self._tmpl is None: self._tmpl = TransTmpl(self._structT) if self._frames is None: DW = self.DATA_WIDTH frames = FrameTmpl.framesFromTransTmpl( self._tmpl, DW, trimPaddingWordsOnStart=True, trimPaddingWordsOnEnd=True) self._frames = list(frames) def _declr(self): addClkRstn(self) self.dataOut = StructIntf(self._structT, tuple(), self._mkFieldIntf)._m() g = self.get = Handshaked() # data signal is addr of structure to download g.DATA_WIDTH = self.ADDR_WIDTH self.parseTemplate() with self._paramsShared(): # interface for communication with datapump self.rDatapump = AxiRDatapumpIntf()._m() self.rDatapump.MAX_BYTES = self.maxBytesInTransaction() with self._paramsShared(exclude=({"ID_WIDTH"}, set())): self.parser = AxiS_frameParser(self._structT, tmpl=self._tmpl, frames=self._frames) self.parser.SYNCHRONIZE_BY_LAST = False if self.SHARED_READY: self.ready = Signal() def driveReqRem(self, req: AddrSizeHs, MAX_BITS: int): return req.rem(ceil((MAX_BITS % self.DATA_WIDTH) / 8)) def _impl(self): propagateClkRstn(self) req = self.rDatapump.req if self.READ_ACK: get = self.get else: get = HsBuilder(self, self.get).buff().end def propagateRequest(frame, indx): isLastFrame = indx == len(self._frames) - 1 s = [ req.addr(get.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), self.driveReqRem(req, frame.parts[-1].endOfPart - frame.startBitAddr), req.vld(get.vld), get.rd(req.rd if isLastFrame else 0) ] ack = StreamNode(masters=[get], slaves=[self.rDatapump.req]).ack() return s, ack StaticForEach(self, self._frames, propagateRequest) r = self.rDatapump.r data_sig_to_exclude = [] if self.ID_WIDTH: req.id(self.ID) if hasattr(r, "id"): data_sig_to_exclude.append(r.id) if hasattr(r, "strb"): data_sig_to_exclude.append(r.strb) self.parser.dataIn(r, exclude=data_sig_to_exclude) for _, field in self._tmpl.walkFlatten(): p = field.getFieldPath() myIntf = self.dataOut._fieldsToInterfaces[p] parserIntf = self.parser.dataOut._fieldsToInterfaces[p] myIntf(parserIntf)