Esempio n. 1
0
    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
Esempio n. 2
0
    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)
Esempio n. 3
0
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)
Esempio n. 4
0
    def _declr(self):
        addClkRstn(self)

        with self._paramsShared():
            self.r = RamHsR()
            self.w = AddrDataHs()

            self.conv = RamAsHs()
            self.ram = RamSingleClock()
Esempio n. 5
0
    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
Esempio n. 6
0
    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()
Esempio n. 7
0
    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()
Esempio n. 8
0
    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,)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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
Esempio n. 11
0
    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()
Esempio n. 12
0
    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
Esempio n. 13
0
    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)
Esempio n. 14
0
 def setUpClass(cls):
     u = cls.u = RamSingleClock()
     u.DATA_WIDTH = 8
     u.ADDR_WIDTH = 3
     cls.compileSim(u)
Esempio n. 15
0
 def _config(self):
     RamSingleClock._config(self)
Esempio n. 16
0
    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)
Esempio n. 17
0
 def _config(self):
     RamSingleClock._config(self)
     self.PORT_CNT = (WRITE, WRITE, READ)
     self.PRIMITIVE_MEMORY_PORTS = Param((WRITE, READ))
Esempio n. 18
0
 def _config(self):
     RamSingleClock._config(self)
Esempio n. 19
0
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)
Esempio n. 20
0
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)
Esempio n. 21
0
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()