def _declr(self): assert self.HAS_BE assert len( self.PORT_CNT) >= 2, "Requres at least 1 WRITE and 1 READ port" assert self.PORT_CNT == ( WRITE, *(READ for _ in range(len(self.PORT_CNT) - 1))),\ self.PORT_CNT addClkRstn(self) RamSingleClock._declr_ports(self) self.MASK_W = self.DATA_WIDTH // 8 # padding to make mask width % 8 == 0 self.MASK_PADDING_W = ceil(self.MASK_W / 8) * 8 - self.MASK_W with self._paramsShared(exclude=({"DATA_WIDTH"}, {})): ram = self.ram = RamSingleClock() ram.DATA_WIDTH = self.DATA_WIDTH + self.MASK_PADDING_W + self.MASK_W
def _declr(self) -> None: addClkRstn(self) with self._paramsShared(): self.s = Axi4() self.ram = RamSingleClock() self.ram.ADDR_WIDTH = self.ADDR_WIDTH - log2ceil(self.DATA_WIDTH // 8 - 1)
class RamWithHs(RamAsHs): def _declr(self): addClkRstn(self) with self._paramsShared(): self.r = RamHsR() self.w = AddrDataHs() self.conv = RamAsHs() self.ram = RamSingleClock() def _impl(self): propagateClkRstn(self) self.conv.r(self.r) self.conv.w(self.w) self.ram.a(self.conv.ram)
def _declr(self): addClkRstn(self) with self._paramsShared(): self.r = RamHsR() self.w = AddrDataHs() self.conv = RamAsHs() self.ram = RamSingleClock()
def _declr(self): HashTableCoreWithRam._declr_common(self) t = self.table = RamSingleClock() t.PORT_CNT = 1 t.ADDR_WIDTH = log2ceil(self.ITEMS_CNT) t.DATA_WIDTH = self.KEY_WIDTH + self.DATA_WIDTH + 1 # +1 for item_vld tc = self.tableConnector = RamAsHs() tc.ADDR_WIDTH = t.ADDR_WIDTH tc.DATA_WIDTH = t.DATA_WIDTH
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): PORT_CNT = int(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): addClkRstn(self) with self._paramsShared(): if self.HAS_R: self.r = RamHsR() if self.HAS_W: self.w = AddrDataHs() self.conv = RamAsHs() r = self.ram = RamSingleClock() if not self.HAS_W: assert self.INIT_DATA is not None assert self.HAS_R r.PORT_CNT = (READ,) elif not self.HAS_R: assert self.HAS_W r.PORT_CNT = (WRITE,)
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): self.PAGE_OFFSET_WIDTH = log2ceil(self.PAGE_SIZE) self.LVL1_PAGE_TABLE_INDX_WIDTH = log2ceil(self.LVL1_PAGE_TABLE_ITEMS) self.LVL2_PAGE_TABLE_INDX_WIDTH = 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_BYTES = self.DATA_WIDTH // 8 i = self.virtIn = Handshaked() i.DATA_WIDTH = self.VIRT_ADDR_WIDTH i = self.physOut = Handshaked()._m() i.DATA_WIDTH = self.ADDR_WIDTH self.segfault = Signal()._m() self.lvl1Table = BramPort_withoutClk() # internal components self.lvl1Storage = RamSingleClock() self.lvl1Storage.PORT_CNT = 1 self.lvl1Converter = RamAsHs() for u in [self.lvl1Table, self.lvl1Converter, self.lvl1Storage]: u.DATA_WIDTH = self.ADDR_WIDTH u.ADDR_WIDTH = self.LVL1_PAGE_TABLE_INDX_WIDTH with self._paramsShared(): self.lvl2get = ArrayItemGetter() self.lvl2get.ITEM_WIDTH = self.ADDR_WIDTH self.lvl2get.ITEMS = self.LVL2_PAGE_TABLE_ITEMS self.lvl2indxFifo = HandshakedFifo(Handshaked) self.lvl2indxFifo.DEPTH = self.MAX_OVERLAP // 2 self.lvl2indxFifo.DATA_WIDTH = self.LVL2_PAGE_TABLE_INDX_WIDTH self.pageOffsetFifo = HandshakedFifo(Handshaked) self.pageOffsetFifo.DEPTH = self.MAX_OVERLAP self.pageOffsetFifo.DATA_WIDTH = self.PAGE_OFFSET_WIDTH
def _declr(self): addClkRstn(self) self._init_constants() with self._paramsShared(): self.m = Axi4()._m() self.ooo_fifo = FifoOutOfOrderRead() self.ooo_fifo.ITEMS = 2 ** self.ID_WIDTH sa = self.state_array = RamSingleClock() sa.PORT_CNT = (WRITE, READ) sa.ADDR_WIDTH = self.ID_WIDTH TRANSACTION_STATE_T = self.TRANSACTION_STATE_T # address + TRANSACTION_STATE_T sa.DATA_WIDTH = self.MAIN_STATE_INDEX_WIDTH + ( 0 if TRANSACTION_STATE_T is None else TRANSACTION_STATE_T.bit_length() ) self._declr_io()
def _declr(self): self._compupte_tag_index_offset_widths() self.tag_record_t = self.define_tag_record_t() addClkRstn(self) with self._paramsShared(): self.lookup = HObjList(AddrHs() for _ in range(self.PORT_CNT)) self.lookupRes = HObjList(AxiCacheTagArrayLookupResIntf()._m() for _ in range(self.PORT_CNT)) for i in self.lookupRes: i.TAG_T = self.tag_record_t self.update = HObjList(AxiCacheTagArrayUpdateIntf() for _ in range(self.UPDATE_PORT_CNT)) tag_mem = self.tag_mem = RamSingleClock() tag_mem.ADDR_WIDTH = log2ceil(self.CACHE_LINE_CNT // self.WAY_CNT - 1) tag_mem.DATA_WIDTH = self.tag_record_t.bit_length() * self.WAY_CNT tag_mem.MAX_BLOCK_DATA_WIDTH = self.MAX_BLOCK_DATA_WIDTH tag_mem.PORT_CNT = ( *(WRITE for _ in range(self.UPDATE_PORT_CNT)), *(READ for _ in range(self.PORT_CNT)), ) tag_mem.HAS_BE = True
def _declr(self): addClkRstn(self) assert int(self.KEY_WIDTH) > 0 assert int(self.DATA_WIDTH) >= 0 assert int(self.ITEMS_CNT) > 1 self.HASH_WITH = log2ceil(self.ITEMS_CNT).val assert self.HASH_WITH < int(self.KEY_WIDTH), ( "It makes no sense to use hash table when you can use key directly as index", self.HASH_WITH, self.KEY_WIDTH) with self._paramsShared(): self.insert = InsertIntf() self.insert.HASH_WIDTH.set(self.HASH_WITH) self.lookup = LookupKeyIntf() self.lookupRes = LookupResultIntf()._m() self.lookupRes.HASH_WIDTH.set(self.HASH_WITH) t = self.table = RamSingleClock() t.PORT_CNT.set(1) t.ADDR_WIDTH.set(log2ceil(self.ITEMS_CNT)) t.DATA_WIDTH.set(self.KEY_WIDTH + self.DATA_WIDTH + 1) # +1 for vldFlag tc = self.tableConnector = RamAsHs() tc.ADDR_WIDTH.set(t.ADDR_WIDTH.get()) tc.DATA_WIDTH.set(t.DATA_WIDTH.get()) hashWidth = max(int(self.KEY_WIDTH), int(self.HASH_WITH)) h = self.hash = CrcComb() h.DATA_WIDTH.set(hashWidth) h.setConfig(self.POLYNOME) h.POLY_WIDTH.set(hashWidth)
def setUpClass(cls): u = cls.u = RamSingleClock() u.DATA_WIDTH = 8 u.ADDR_WIDTH = 3 cls.compileSim(u)
def _config(self): RamSingleClock._config(self)
def _impl(self): if self._can_be_primitive_ram: super(RamXorSingleClock, self)._impl() else: if self.PRIMITIVE_MEMORY_PORTS != (WRITE, READ): raise NotImplementedError(self.PRIMITIVE_MEMORY_PORTS) if self._rw_ports: raise NotImplementedError("RW ports (supports only write and read ports)") r_ports = self._r_ports assert r_ports w_ports = self._w_ports assert w_ports # 1. construct a matrix N x N where N is a number of wrie ports # the diagonal is set to None because we do not need to synchronize the port with itself w_rams = HObjList( HObjList( RamSingleClock() if x != y else None for x in w_ports ) for y in w_ports) # construct a matrix M x N where M is number of read ports r_rams = HObjList(HObjList(RamSingleClock() for _ in w_ports) for _ in range(len(r_ports))) for row in w_rams + r_rams: for r in row: if r is None: continue r._updateParamsFrom(self, exclude=(("PORT_CNT",), ())) r.PORT_CNT = self.PRIMITIVE_MEMORY_PORTS if self.INIT_DATA is not None: raise NotImplementedError() r.INIT_DATA = tuple(0 for _ in range(2 ** r.ADDR_WIDTH)) self.w_rams = w_rams self.r_rams = r_rams # :type: List[Tuple[RtlSignal, RtlSignal, RtlSignal]] # List of tuples (en, address, write data), used for write forwarding on read ports write_in_progress_staus = [] # 2. connect them with XOR logic # add the register on write address and data because we need to load the data for XOR first for i, w in enumerate(w_ports): xor_src = [] for mem in w_rams[i]: if mem is not None: xor_src.append(mem) xor_loaded_src = [] for s in xor_src: p = s.port[1] p.addr(w.addr) p.en(w.en) xor_loaded_src.append(p.dout) w_addr_reg = self._reg(f"{w._name}_addr_reg", w.addr._dtype) w_addr_reg(w.addr) w_en_reg = self._reg(f"{w._name}_en_reg", def_val=0) w_en_reg(w.en) w_data_reg = self._reg(f"{w._name}_data_reg", w.din._dtype) w_data_reg(w.din) xored_data = Xor(w_data_reg, *xor_loaded_src) for ram_row in w_rams + r_rams: xor_dst = ram_row[i] if xor_dst is None: continue xor_dst = xor_dst.port[0] xor_dst.addr(w_addr_reg) xor_dst.en(w_en_reg) xor_dst.din(xored_data) write_in_progress_staus.append((w_en_reg, w_addr_reg, xored_data)) # 3. connect read ports to memories for (i, r), r_ram_column in zip(enumerate(r_ports), r_rams): out_xor_inputs = [] for r_ram, (w_en_reg, w_addr_reg, w_xored_data) in zip(r_ram_column, write_in_progress_staus): r_ram = r_ram.port[1] s = (w_en_reg & w_addr_reg._eq(r.addr))._ternary(w_xored_data, r_ram.dout) out_xor_inputs.append(s) r_ram.addr(r.addr) r_ram.en(r.en) r.dout(Xor(*out_xor_inputs)) propagateClk(self)
def _config(self): RamSingleClock._config(self) self.PORT_CNT = (WRITE, WRITE, READ) self.PRIMITIVE_MEMORY_PORTS = Param((WRITE, READ))
class MMU_2pageLvl(Unit): """ MMU where parent page table is stored in ram this unit and only items from leaf page tables are download on each request over rDatapump interface :attention: if item in pagetable is BAD_PHYS_ADDR output signal segfault becomes 1 and unit will stop working :attention: rootPageTable has to be initialized before first request over virtIn interface :attention: rootPageTable has write only access :attention: use value -1 to mark that page is not mapped, it will result in segfault signal asserted high when this address is accessed .. hwt-schematic:: """ def _config(self): # width of id signal for bus self.ID_WIDTH = Param(1) self.ADDR_WIDTH = Param(32) self.DATA_WIDTH = Param(64) self.VIRT_ADDR_WIDTH = Param(32) self.LVL1_PAGE_TABLE_ITEMS = Param(512) self.PAGE_SIZE = Param(int(2 ** 12)) self.MAX_OVERLAP = Param(16) 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 connectLvl1PageTable(self): rpgt = self.lvl1Table rootW = self.lvl1Converter.w rpgt.dout(None) rootW.addr(rpgt.addr) wEn = rpgt.en & rpgt.we rootW.vld(wEn) rootW.data(rpgt.din) self.lvl1Storage.a(self.lvl1Converter.ram) lvl1read = self.lvl1Converter.r return lvl1read def connectL1Load(self, lvl1readAddr): virtIn = self.virtIn lvl2indx = self.lvl2indxFifo.dataIn pageOffset = self.pageOffsetFifo lvl2indx.data(virtIn.data[(self.LVL2_PAGE_TABLE_INDX_WIDTH + self.PAGE_OFFSET_WIDTH):self.PAGE_OFFSET_WIDTH]) connect(virtIn.data, pageOffset.dataIn.data, fit=True) lvl1readAddr.data(virtIn.data[:(self.LVL2_PAGE_TABLE_INDX_WIDTH + self.PAGE_OFFSET_WIDTH)]) StreamNode(masters=[virtIn], slaves=[lvl2indx, lvl1readAddr, pageOffset.dataIn]).sync() def connectL2Load(self, lvl2base, segfaultFlag): lvl2get = self.lvl2get lvl2indx = self.lvl2indxFifo.dataOut self.rDatapump(lvl2get.rDatapump) lvl2get.base(lvl2base.data) lvl2get.index.data(lvl2indx.data) StreamNode(masters=[lvl2base, lvl2indx], slaves=[lvl2get.index], extraConds={ lvl2get.index:~segfaultFlag }).sync() def connectPhyout(self, segfaultFlag): phyAddrBase = self.lvl2get.item pageOffset = self.pageOffsetFifo.dataOut segfault = segfaultFlag | phyAddrBase.data[0]._eq(FLAG_INVALID) StreamNode(masters=[phyAddrBase, pageOffset], slaves=[self.physOut], extraConds={self.physOut:~segfault}).sync() self.physOut.data(Concat(phyAddrBase.data[:self.PAGE_OFFSET_WIDTH], pageOffset.data)) def segfaultChecker(self): lvl1item = self.lvl1Converter.r.data lvl2item = self.lvl2get.item segfaultFlag = self._reg("segfaultFlag", defVal=False) def errVal(intf): return intf.vld & intf.data[0]._eq(FLAG_INVALID) If(errVal(lvl1item) | errVal(lvl2item), segfaultFlag(1) ) return segfaultFlag def _impl(self): propagateClkRstn(self) segfaultFlag = self.segfaultChecker() lvl1read = self.connectLvl1PageTable() self.connectL1Load(lvl1read.addr) self.connectL2Load(lvl1read.data, segfaultFlag) self.connectPhyout(segfaultFlag) self.segfault(segfaultFlag)
class MMU_2pageLvl(Unit): """ MMU where parent page table is stored in ram this unit and only items from leaf page tables are download on each request over rDatapump interface :attention: if item in pagetable is BAD_PHYS_ADDR output signal segfault becomes 1 and unit will stop working :attention: rootPageTable has to be initialized before first request over virtIn interface :attention: rootPageTable has write only access :attention: use value -1 to mark that page is not mapped, it will result in segfault signal asserted high when this address is accessed .. hwt-schematic:: """ def _config(self): # width of id signal for bus self.ID_WIDTH = Param(1) self.ADDR_WIDTH = Param(32) self.DATA_WIDTH = Param(64) self.VIRT_ADDR_WIDTH = Param(32) self.LVL1_PAGE_TABLE_ITEMS = Param(512) self.PAGE_SIZE = Param(int(2**12)) self.MAX_OVERLAP = Param(16) 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 connectLvl1PageTable(self): rpgt = self.lvl1Table rootW = self.lvl1Converter.w rpgt.dout(None) rootW.addr(rpgt.addr) wEn = rpgt.en & rpgt.we rootW.vld(wEn) rootW.data(rpgt.din) self.lvl1Storage.a(self.lvl1Converter.ram) lvl1read = self.lvl1Converter.r return lvl1read def connectL1Load(self, lvl1readAddr): virtIn = self.virtIn lvl2indx = self.lvl2indxFifo.dataIn pageOffset = self.pageOffsetFifo lvl2indx.data( virtIn.data[(self.LVL2_PAGE_TABLE_INDX_WIDTH + self.PAGE_OFFSET_WIDTH):self.PAGE_OFFSET_WIDTH]) connect(virtIn.data, pageOffset.dataIn.data, fit=True) lvl1readAddr.data(virtIn.data[:(self.LVL2_PAGE_TABLE_INDX_WIDTH + self.PAGE_OFFSET_WIDTH)]) StreamNode(masters=[virtIn], slaves=[lvl2indx, lvl1readAddr, pageOffset.dataIn]).sync() def connectL2Load(self, lvl2base, segfaultFlag): lvl2get = self.lvl2get lvl2indx = self.lvl2indxFifo.dataOut self.rDatapump(lvl2get.rDatapump) lvl2get.base(lvl2base.data) lvl2get.index.data(lvl2indx.data) StreamNode(masters=[lvl2base, lvl2indx], slaves=[lvl2get.index], extraConds={ lvl2get.index: ~segfaultFlag }).sync() def connectPhyout(self, segfaultFlag): phyAddrBase = self.lvl2get.item pageOffset = self.pageOffsetFifo.dataOut segfault = segfaultFlag | phyAddrBase.data[0]._eq(FLAG_INVALID) StreamNode(masters=[phyAddrBase, pageOffset], slaves=[self.physOut], extraConds={ self.physOut: ~segfault }).sync() self.physOut.data( Concat(phyAddrBase.data[:self.PAGE_OFFSET_WIDTH], pageOffset.data)) def segfaultChecker(self): lvl1item = self.lvl1Converter.r.data lvl2item = self.lvl2get.item segfaultFlag = self._reg("segfaultFlag", defVal=False) def errVal(intf): return intf.vld & intf.data[0]._eq(FLAG_INVALID) If(errVal(lvl1item) | errVal(lvl2item), segfaultFlag(1)) return segfaultFlag def _impl(self): propagateClkRstn(self) segfaultFlag = self.segfaultChecker() lvl1read = self.connectLvl1PageTable() self.connectL1Load(lvl1read.addr) self.connectL2Load(lvl1read.data, segfaultFlag) self.connectPhyout(segfaultFlag) self.segfault(segfaultFlag)
class FlipRam(Unit): """ Switchable RAM, there are two memories and two sets of ports, Each set of ports is every time connected to opposite ram. By select you can choose between RAMs. This component is meant to be form of synchronization. Example first RAM is connected to first set of ports, writer performs actualizations on first RAM and reader reads data from second ram by second set of ports. Then select is set and access is flipped. Reader now has access to RAM 0 and writer to RAM 1. .. hwt-schematic:: """ def _config(self): RamSingleClock._config(self) def _declr(self): PORT_CNT = int(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 _impl(self): propagateClk(self) PORT_CNT = int(self.PORT_CNT) fa = self.firstA sa = self.secondA If(self.select_sig, self.ram0.a(fa), self.ram1.a(sa) ).Else( self.ram0.a(sa), self.ram1.a(fa) ) if PORT_CNT == 2: fb = self.firstB sb = self.secondB If(self.select_sig, self.ram0.b(fb), self.ram1.b(sb), ).Else( self.ram0.b(sb), self.ram1.b(fb) ) elif PORT_CNT > 2: raise NotImplementedError()