def connect_update_port(self, update: AxiCacheTagArrayUpdateIntf, tag_mem_port_w: BramPort_withoutClk): update_tmp = self._reg("update_tmp", HStruct( (update.addr._dtype, "addr"), (BIT, "delete"), (update.way_en._dtype, "way_en"), (BIT, "vld"), ), def_val={"vld": 0}) update_tmp(update) tag, index, _ = self.parse_addr(update.addr) tag_mem_port_w.en(update.vld) tag_mem_port_w.addr(index) # construct the byte enable mask for various tag enable configurations # prepare write tag in every way but byte enable only requested ways tag_record = self.tag_record_t.from_py({ "tag": tag, "valid": ~update.delete, }) tag_record = tag_record._reinterpret_cast( Bits(self.tag_record_t.bit_length())) tag_mem_port_w.din(Concat(*(tag_record for _ in range(self.WAY_CNT)))) tag_be_t = Bits(self.tag_record_t.bit_length() // 8) tag_en = tag_be_t.from_py(tag_be_t.all_mask()) tag_not_en = tag_be_t.from_py(0) tag_mem_port_w.we( Concat(*reversed( [en._ternary(tag_en, tag_not_en) for en in update.way_en]))) return update_tmp
def _mkFieldInterface(self, structIntf: StructIntf, field: HStructField): """ Instantiate field interface for fields in structure template of this endpoint :return: interface for specified field """ t = field.dtype path = structIntf._field_path / field.name shouldEnter, shouldUse = self.shouldEnterFn(self.STRUCT_TEMPLATE, path) if shouldUse: if isinstance(t, Bits): p = BusEndpoint.intf_for_Bits(t) elif isinstance(t, HArray): p = BramPort_withoutClk() assert isinstance(t.element_t, Bits), t.element_t p.DATA_WIDTH = t.element_t.bit_length() p.ADDR_WIDTH = log2ceil(t.size - 1) else: raise NotImplementedError(t) elif shouldEnter: if isinstance(t, HArray): e_t = t.element_t if isinstance(e_t, Bits): p = HObjList() for i_i in range(int(t.size)): i = BusEndpoint.intf_for_Bits(e_t) structIntf._fieldsToInterfaces[path / i_i] = i p.append(i) elif isinstance(e_t, HStruct): p = HObjList( StructIntf(t.element_t, path / i, instantiateFieldFn=self._mkFieldInterface) for i in range(int(t.size))) for i in p: i._fieldsToInterfaces = structIntf._fieldsToInterfaces else: raise NotImplementedError() elif isinstance(t, HStruct): p = StructIntf(t, path, instantiateFieldFn=self._mkFieldInterface) p._fieldsToInterfaces = structIntf._fieldsToInterfaces else: raise TypeError(t) return p
def connectPort(self, port: BramPort_withoutClk, mem: RtlSignal): If(self.clk._onRisingEdge() & port.en, If(port.we, mem[port.addr](port.din) ), port.dout(mem[port.addr]) )
def _mkFieldInterface(self, structIntf: HStruct, field: HStructField): t = field.dtype if isinstance(t, Bits): p = RegCntrl() dw = t.bit_length() elif isinstance(t, HArray): field_path = structIntf._field_path / field.name if self.shouldEnterFn(field_path)[0]: if isinstance(t.element_t, Bits): p = HObjList(RegCntrl() for _ in range(int(t.size))) dw = t.element_t.bit_length() else: p = HObjList([StructIntf( t.element_t, field_path, instantiateFieldFn=self._mkFieldInterface) for _ in range(int(t.size))]) return p else: p = BramPort_withoutClk() dw = t.element_t.bit_length() p.ADDR_WIDTH = log2ceil(int(t.size) - 1) else: raise NotImplementedError(t) p.DATA_WIDTH = dw return p
def _mkFieldInterface(self, structIntf, field): t = field.dtype if isinstance(t, Bits): p = RegCntrl() dw = t.bit_length() elif isinstance(t, HArray): if self.shouldEnterFn(field): if isinstance(t.elmType, Bits): p = HObjList(RegCntrl() for _ in range(int(t.size))) dw = t.elmType.bit_length() else: p = HObjList([ StructIntf(t.elmType, instantiateFieldFn=self._mkFieldInterface) for _ in range(int(t.size)) ]) return p else: p = BramPort_withoutClk() dw = t.elmType.bit_length() p.ADDR_WIDTH.set(log2ceil(int(t.size) - 1)) else: raise NotImplementedError(t) p.DATA_WIDTH.set(dw) return p
def _declr(self): PORTS = int(self.PORT_CNT) self.clk = Clk() with self._paramsShared(): # to let IDEs resolve type of port self.a = BramPort_withoutClk() for i in range(PORTS - 1): self._sportPort(i + 1)
def _declr(self): PORT_CNT = self.PORT_CNT with self._paramsShared(): self.clk = Clk() # to let IDEs resolve type of port self.firstA = BramPort_withoutClk() self.secondA = BramPort_withoutClk() if PORT_CNT == 2: self.firstB = BramPort_withoutClk() self.secondB = BramPort_withoutClk() elif PORT_CNT > 2: raise NotImplementedError() self.select_sig = Signal() self.ram0 = RamSingleClock() self.ram1 = RamSingleClock()
def _declr(self): assert self.HAS_R or self.HAS_W addClkRstn(self) with self._paramsShared(): if self.HAS_R: self.r = RamHsR() if self.HAS_W: self.w = AddrDataHs() self.w.HAS_MASK = self.HAS_BE self.ram = BramPort_withoutClk()._m()
def _mkFieldInterface(self, structIntf, field): """ Instantiate field interface for fields in structure template of this endpoint :return: interface for specified field """ t = field.dtype DW = int(self.DATA_WIDTH) shouldEnter, shouldUse = self.shouldEnterFn(field) if shouldUse: if isinstance(t, Bits): p = RegCntrl() dw = t.bit_length() elif isinstance(t, HArray): p = BramPort_withoutClk() assert isinstance(t.elmType, Bits), t.elmType dw = t.elmType.bit_length() p.ADDR_WIDTH.set(log2ceil(t.size - 1)) else: raise NotImplementedError(t) elif shouldEnter: if isinstance(t, HArray): if isinstance(t.elmType, Bits): p = HObjList(RegCntrl() for _ in range(int(t.size))) dw = t.elmType.bit_length() else: return HObjList( StructIntf(t.elmType, instantiateFieldFn=self._mkFieldInterface) for _ in range(int(t.size))) elif isinstance(t, HStruct): return StructIntf(t, instantiateFieldFn=self._mkFieldInterface) else: raise TypeError(t) if isinstance(p, HObjList): _p = p else: _p = [p] if dw == DW: # use param instead of value to improve readability DW = self.DATA_WIDTH if isinstance(DW, Param): for i in _p: i._replaceParam(i.DATA_WIDTH, DW) else: for i in _p: i.DATA_WIDTH.set(dw) return p
def connect_port(clk: RtlSignal, port: BramPort_withoutClk, mem: RtlSignal): if port.HAS_R and port.HAS_W: If(clk._onRisingEdge(), If(port.en, *RamSingleClock.mem_write(mem, port), port.dout(mem[port.addr]) ) ) elif port.HAS_R: If(clk._onRisingEdge(), If(port.en, port.dout(mem[port.addr]) ) ) elif port.HAS_W: If(clk._onRisingEdge(), If(port.en, *RamSingleClock.mem_write(mem, port), ) ) else: raise AssertionError("Bram port has to have at least write or read part")
def _declr(self): self.PAGE_OFFSET_WIDTH = log2ceil(self.PAGE_SIZE).val self.LVL1_PAGE_TABLE_INDX_WIDTH = log2ceil( self.LVL1_PAGE_TABLE_ITEMS).val self.LVL2_PAGE_TABLE_INDX_WIDTH = int(self.ADDR_WIDTH - self.LVL1_PAGE_TABLE_INDX_WIDTH - self.PAGE_OFFSET_WIDTH) self.LVL2_PAGE_TABLE_ITEMS = 2**int(self.LVL2_PAGE_TABLE_INDX_WIDTH) assert self.LVL1_PAGE_TABLE_INDX_WIDTH > 0, self.LVL1_PAGE_TABLE_INDX_WIDTH assert self.LVL2_PAGE_TABLE_INDX_WIDTH > 0, self.LVL2_PAGE_TABLE_INDX_WIDTH assert self.LVL2_PAGE_TABLE_ITEMS > 1, self.LVL2_PAGE_TABLE_ITEMS # public interfaces addClkRstn(self) with self._paramsShared(): self.rDatapump = AxiRDatapumpIntf()._m() self.rDatapump.MAX_LEN.set(1) i = self.virtIn = Handshaked() i._replaceParam(i.DATA_WIDTH, self.VIRT_ADDR_WIDTH) i = self.physOut = Handshaked()._m() i._replaceParam(i.DATA_WIDTH, self.ADDR_WIDTH) self.segfault = Signal()._m() self.lvl1Table = BramPort_withoutClk() # internal components self.lvl1Storage = RamSingleClock() self.lvl1Storage.PORT_CNT.set(1) self.lvl1Converter = RamAsHs() for u in [self.lvl1Table, self.lvl1Converter, self.lvl1Storage]: u.DATA_WIDTH.set(self.ADDR_WIDTH) u.ADDR_WIDTH.set(self.LVL1_PAGE_TABLE_INDX_WIDTH) with self._paramsShared(): self.lvl2get = ArrayItemGetter() self.lvl2get.ITEM_WIDTH.set(self.ADDR_WIDTH) self.lvl2get.ITEMS.set(self.LVL2_PAGE_TABLE_ITEMS) self.lvl2indxFifo = HandshakedFifo(Handshaked) self.lvl2indxFifo.DEPTH.set(self.MAX_OVERLAP // 2) self.lvl2indxFifo.DATA_WIDTH.set(self.LVL2_PAGE_TABLE_INDX_WIDTH) self.pageOffsetFifo = HandshakedFifo(Handshaked) self.pageOffsetFifo.DEPTH.set(self.MAX_OVERLAP) self.pageOffsetFifo.DATA_WIDTH.set(self.PAGE_OFFSET_WIDTH)
def _declr(self): addClkRstn(self) with self._paramsShared(): self.bus = Axi4Lite() self.signalLoop = SigLoop() self.signalIn = VectSignal(self.DATA_WIDTH) self.regCntrlLoop = Loop(RegCntrl) self.regCntrlOut = RegCntrl()._m() self.vldSyncedLoop = Loop(VldSynced) self.vldSyncedOut = VldSynced()._m() with self._paramsShared(exclude=({"ADDR_WIDTH"}, set())): self.bramLoop = Loop(BramPort_withoutClk) self.bramLoop.ADDR_WIDTH = 2 self.bramOut = BramPort_withoutClk()._m() self.bramOut.ADDR_WIDTH = 2
def connectPort(self, port: BramPort_withoutClk, mem: RtlSignal): If(self.clk._onRisingEdge() & port.en, If(port.we, mem[port.addr](port.din)), port.dout(mem[port.addr]))
def _declr(self): addClkRst(self) self.din = BramPort_withoutClk() self.dout = BramPort_withoutClk()._m()
def _config(self): BramPort_withoutClk._config(self)
def _sportPort(self, index) -> None: name = self.genPortName(index) setattr(self, name, BramPort_withoutClk())
def connect_lookup_port(self, lookup: AddrHs, tag_mem_port_r: BramPort_withoutClk, lookupRes: AxiCacheTagArrayLookupResIntf, update_tmp: StructIntf): lookup_tmp = self._reg( "lookup_tmp", HStruct(*([(lookup.id._dtype, "id")] if lookup.ID_WIDTH else ()), (lookup.addr._dtype, "addr"), (BIT, "vld")), def_val={"vld": 0}) pa = self.parse_addr just_updated = rename_signal( self, # updated on same index (using "update" port) = the result which is currently on output # of the ram may be invalid update_tmp.vld & pa(lookup_tmp.addr)[1]._eq(pa(update_tmp.addr)[1]), "just_updated") # tag comparator tag, _, _ = self.parse_addr(lookup_tmp.addr) tags = tag_mem_port_r.dout._reinterpret_cast( self.tag_record_t[self.WAY_CNT]) found = [ # is matching and just this tag was not updated (t.valid & t.tag._eq(tag) & (~just_updated | (update_tmp.vld & ~update_tmp.way_en[i]))) | ( # or was updated to the matching tag just_updated & update_tmp.way_en[i] & ~update_tmp.delete & pa(lookup_tmp.addr)[0]._eq(pa(update_tmp.addr)[0])) for i, t in enumerate(tags) ] # if the data which is currently on output of the ram was # just updated it means that the data is invalid and the update # data will be lost in next clock cycle, if the consumer of lookupRes # can not consume the data just know, we need to perform lookup in tag_array # once again lookup.rd(~lookup_tmp.vld | lookupRes.rd) If( lookup.rd, lookup_tmp.id(lookup.id) if lookup.ID_WIDTH else [], lookup_tmp.addr(lookup.addr), ) lookup_tmp.vld(lookup.vld | (lookup_tmp.vld & ~lookupRes.rd)) tag_mem_port_r.addr((lookup_tmp.vld & ~lookupRes.rd)._ternary( self.parse_addr(lookup_tmp.addr) [1], # lookup previous address and look for a change self.parse_addr(lookup.addr)[1], # lookup a new address )) tag_mem_port_r.en(lookup.vld | (lookup_tmp.vld & ~lookupRes.rd)) if lookupRes.ID_WIDTH: lookupRes.id(lookup_tmp.id) lookupRes.addr(lookup_tmp.addr) lookupRes.way(oneHotToBin(self, found)) lookupRes.found(Or(*found)) lookupRes.tags(tags) lookupRes.vld(lookup_tmp.vld)
def _declr(self): addClkRstn(self) with self._paramsShared(): self.r = RamHsR() self.w = AddrDataHs() self.ram = BramPort_withoutClk()._m()