Example #1
0
    def elaborate(self, platform):
        m = Module()

        ack_fanin = 0
        err_fanin = 0
        rty_fanin = 0
        stall_fanin = 0

        with m.Switch(self.bus.adr):
            for sub_map, (sub_pat, sub_ratio) in self._map.window_patterns():
                sub_bus = self._subs[sub_map]

                m.d.comb += [
                    sub_bus.adr.eq(self.bus.adr << log2_int(sub_ratio)),
                    sub_bus.dat_w.eq(self.bus.dat_w),
                    sub_bus.sel.eq(
                        Cat(Repl(sel, sub_ratio) for sel in self.bus.sel)),
                    sub_bus.we.eq(self.bus.we),
                    sub_bus.stb.eq(self.bus.stb),
                ]
                if hasattr(sub_bus, "lock"):
                    m.d.comb += sub_bus.lock.eq(getattr(self.bus, "lock", 0))
                if hasattr(sub_bus, "cti"):
                    m.d.comb += sub_bus.cti.eq(
                        getattr(self.bus, "cti", CycleType.CLASSIC))
                if hasattr(sub_bus, "bte"):
                    m.d.comb += sub_bus.bte.eq(
                        getattr(self.bus, "bte", BurstTypeExt.LINEAR))

                granularity_bits = log2_int(self.bus.data_width //
                                            self.bus.granularity)
                with m.Case(sub_pat[:-granularity_bits
                                    if granularity_bits > 0 else None]):
                    m.d.comb += [
                        sub_bus.cyc.eq(self.bus.cyc),
                        self.bus.dat_r.eq(sub_bus.dat_r),
                    ]
                    ack_fanin |= sub_bus.ack
                    if hasattr(sub_bus, "err"):
                        err_fanin |= sub_bus.err
                    if hasattr(sub_bus, "rty"):
                        rty_fanin |= sub_bus.rty
                    if hasattr(sub_bus, "stall"):
                        stall_fanin |= sub_bus.stall

        m.d.comb += self.bus.ack.eq(ack_fanin)
        if hasattr(self.bus, "err"):
            m.d.comb += self.bus.err.eq(err_fanin)
        if hasattr(self.bus, "rty"):
            m.d.comb += self.bus.rty.eq(rty_fanin)
        if hasattr(self.bus, "stall"):
            m.d.comb += self.bus.stall.eq(stall_fanin)

        return m
Example #2
0
    def __init__(self, csr_bus, *, data_width=None, name=None):
        if not isinstance(csr_bus, CSRInterface):
            raise ValueError(
                "CSR bus must be an instance of CSRInterface, not {!r}".format(
                    csr_bus))
        if csr_bus.data_width not in (8, 16, 32, 64):
            raise ValueError(
                "CSR bus data width must be one of 8, 16, 32, 64, not {!r}".
                format(csr_bus.data_width))
        if data_width is None:
            data_width = csr_bus.data_width

        self.csr_bus = csr_bus
        self.wb_bus = WishboneInterface(addr_width=max(
            0,
            csr_bus.addr_width - log2_int(data_width // csr_bus.data_width)),
                                        data_width=data_width,
                                        granularity=csr_bus.data_width,
                                        name="wb")

        wb_map = MemoryMap(addr_width=csr_bus.addr_width,
                           data_width=csr_bus.data_width,
                           name=name)
        # Since granularity of the Wishbone interface matches the data width of the CSR bus,
        # no width conversion is performed, even if the Wishbone data width is greater.
        wb_map.add_window(self.csr_bus.memory_map)
        self.wb_bus.memory_map = wb_map
Example #3
0
 def bus(self):
     if self._bus is None:
         self._map.freeze()
         granularity_bits = log2_int(self.data_width // self.granularity)
         self._bus = Interface(addr_width=self._map.addr_width -
                               granularity_bits,
                               data_width=self.data_width,
                               granularity=self.granularity,
                               features=self.features)
         self._bus.memory_map = self._map
     return self._bus
Example #4
0
 def addr_between(base, limit):
     assert base in range(0, 2**30 + 1)
     assert limit in range(0, 2**30 + 1)
     assert limit >= base
     assert base % (limit - base) == 0
     addr_width = log2_int(limit - base, need_pow2=True)
     const_bits = 30 - addr_width
     if const_bits > 0:
         const_pat = "{:0{}b}".format(base >> addr_width, const_bits)
     else:
         const_pat = ""
     return "{}{}".format(const_pat, "-" * addr_width)
Example #5
0
    def window(self, *, addr_width, data_width, granularity=None, features=frozenset(),
               alignment=0, addr=None, sparse=None):
        """Request a window to a subordinate bus.

        See :meth:`amaranth_soc.wishbone.Decoder.add` for details.

        Return value
        ------------
        An instance of :class:`amaranth_soc.wishbone.Interface`.
        """
        window = wishbone.Interface(addr_width=addr_width, data_width=data_width,
                                    granularity=granularity, features=features)
        granularity_bits = log2_int(data_width // window.granularity)
        window.memory_map = MemoryMap(addr_width=addr_width + granularity_bits,
                                      data_width=window.granularity, alignment=alignment)
        self._windows.append((window, addr, sparse))
        return window
Example #6
0
 def memory_map(self, memory_map):
     if not isinstance(memory_map, MemoryMap):
         raise TypeError(
             "Memory map must be an instance of MemoryMap, not {!r}".format(
                 memory_map))
     if memory_map.data_width != self.granularity:
         raise ValueError(
             "Memory map has data width {}, which is not the same as bus "
             "interface granularity {}".format(memory_map.data_width,
                                               self.granularity))
     granularity_bits = log2_int(self.data_width // self.granularity)
     if memory_map.addr_width != max(1, self.addr_width + granularity_bits):
         raise ValueError(
             "Memory map has address width {}, which is not the same as bus "
             "interface address width {} ({} address bits + {} granularity bits)"
             .format(memory_map.addr_width,
                     self.addr_width + granularity_bits, self.addr_width,
                     granularity_bits))
     memory_map.freeze()
     self._map = memory_map
Example #7
0
    def elaborate(self, platform):
        csr_bus = self.csr_bus
        wb_bus = self.wb_bus

        m = Module()

        cycle = Signal(range(len(wb_bus.sel) + 1))
        m.d.comb += csr_bus.addr.eq(
            Cat(cycle[:log2_int(len(wb_bus.sel))], wb_bus.adr))

        with m.If(wb_bus.cyc & wb_bus.stb):
            with m.Switch(cycle):

                def segment(index):
                    return slice(index * wb_bus.granularity,
                                 (index + 1) * wb_bus.granularity)

                for index, sel_index in enumerate(wb_bus.sel):
                    with m.Case(index):
                        if index > 0:
                            # CSR reads are registered, and we need to re-register them.
                            m.d.sync += wb_bus.dat_r[segment(index - 1)].eq(
                                csr_bus.r_data)
                        m.d.comb += csr_bus.r_stb.eq(sel_index & ~wb_bus.we)
                        m.d.comb += csr_bus.w_data.eq(
                            wb_bus.dat_w[segment(index)])
                        m.d.comb += csr_bus.w_stb.eq(sel_index & wb_bus.we)
                        m.d.sync += cycle.eq(index + 1)

                with m.Default():
                    m.d.sync += wb_bus.dat_r[segment(index)].eq(csr_bus.r_data)
                    m.d.sync += wb_bus.ack.eq(1)

        with m.If(wb_bus.ack):
            m.d.sync += cycle.eq(0)
            m.d.sync += wb_bus.ack.eq(0)

        return m
Example #8
0
    def __init__(self,
                 *,
                 addr_width,
                 data_width,
                 granularity=None,
                 features=frozenset(),
                 alignment=0,
                 name=None):
        if granularity is None:
            granularity = data_width
        _check_interface(addr_width, data_width, granularity, features)

        self.data_width = data_width
        self.granularity = granularity
        self.features = set(features)
        self.alignment = alignment

        granularity_bits = log2_int(data_width // granularity)
        self._map = MemoryMap(addr_width=max(1, addr_width + granularity_bits),
                              data_width=granularity,
                              alignment=alignment,
                              name=name)
        self._subs = dict()
        self._bus = None
Example #9
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.dcache = self._dcache

        x_dcache_select = Signal()

        # Test whether the target address is inside the L1 cache region. We use a bit mask in order
        # to avoid carry chains from arithmetic comparisons. To this end, the base and limit
        # addresses of the cached region must satisfy the following constraints:
        # 1) the region size (i.e. ``limit - base``) must be a power of 2
        # 2) ``base`` must be a multiple of the region size

        def addr_between(base, limit):
            assert base in range(0, 2**30 + 1)
            assert limit in range(0, 2**30 + 1)
            assert limit >= base
            assert base % (limit - base) == 0
            addr_width = log2_int(limit - base, need_pow2=True)
            const_bits = 30 - addr_width
            if const_bits > 0:
                const_pat = "{:0{}b}".format(base >> addr_width, const_bits)
            else:
                const_pat = ""
            return "{}{}".format(const_pat, "-" * addr_width)

        dcache_pattern = addr_between(self._dcache.base >> 2,
                                      self._dcache.limit >> 2)
        with m.If(self.x_addr[2:].matches(dcache_pattern)):
            m.d.comb += x_dcache_select.eq(1)

        m_dcache_select = Signal()
        m_addr = Signal.like(self.x_addr)

        with m.If(~self.x_stall):
            m.d.sync += [
                m_dcache_select.eq(x_dcache_select),
                m_addr.eq(self.x_addr),
            ]

        m.d.comb += [
            self._dcache.s1_addr.eq(self.x_addr[2:]),
            self._dcache.s1_stall.eq(self.x_stall),
            self._dcache.s1_valid.eq(self.x_valid),
            self._dcache.s2_addr.eq(m_addr[2:]),
            self._dcache.s2_re.eq(self.m_load & m_dcache_select),
            self._dcache.s2_evict.eq(self.m_store & m_dcache_select),
            self._dcache.s2_flush.eq(self.m_flush),
            self._dcache.s2_valid.eq(self.m_valid),
        ]

        m.submodules.wrbuf = self._wrbuf
        m.d.comb += [
            self._wrbuf.w.en.eq(self.x_store & self.x_valid & x_dcache_select
                                & ~self.x_stall),
            self._wrbuf.w.op.addr.eq(self.x_addr[2:]),
            self._wrbuf.w.op.mask.eq(self.x_mask),
            self._wrbuf.w.op.data.eq(self.x_store_data),
        ]

        dbus_arbiter = m.submodules.dbus_arbiter = WishboneArbiter()
        m.d.comb += dbus_arbiter.bus.connect(self.dbus)

        wrbuf_port = dbus_arbiter.port(priority=0)
        m.d.comb += [
            wrbuf_port.cyc.eq(self._wrbuf.r.rdy),
            wrbuf_port.we.eq(Const(1)),
        ]
        with m.If(wrbuf_port.stb):
            with m.If(wrbuf_port.ack | wrbuf_port.err):
                m.d.sync += wrbuf_port.stb.eq(0)
                m.d.comb += self._wrbuf.r.en.eq(1)
        with m.Elif(self._wrbuf.r.rdy):
            m.d.sync += [
                wrbuf_port.stb.eq(1),
                wrbuf_port.adr.eq(self._wrbuf.r.op.addr),
                wrbuf_port.sel.eq(self._wrbuf.r.op.mask),
                wrbuf_port.dat_w.eq(self._wrbuf.r.op.data),
            ]

        dcache_port = dbus_arbiter.port(priority=1)
        m.d.comb += [
            dcache_port.cyc.eq(self._dcache.bus_re),
            dcache_port.stb.eq(self._dcache.bus_re),
            dcache_port.adr.eq(self._dcache.bus_addr),
            dcache_port.sel.eq(0b1111),
            dcache_port.cti.eq(
                Mux(self._dcache.bus_last, Cycle.END, Cycle.INCREMENT)),
            dcache_port.bte.eq(Const(log2_int(self._dcache.nwords) - 1)),
            self._dcache.bus_valid.eq(dcache_port.ack),
            self._dcache.bus_error.eq(dcache_port.err),
            self._dcache.bus_rdata.eq(dcache_port.dat_r)
        ]

        bare_port = dbus_arbiter.port(priority=2)
        bare_rdata = Signal.like(bare_port.dat_r)
        with m.If(bare_port.cyc):
            with m.If(bare_port.ack | bare_port.err | ~self.m_valid):
                m.d.sync += [
                    bare_port.cyc.eq(0),
                    bare_port.stb.eq(0),
                    bare_rdata.eq(bare_port.dat_r)
                ]
        with m.Elif((self.x_load | self.x_store) & ~x_dcache_select
                    & self.x_valid & ~self.x_stall):
            m.d.sync += [
                bare_port.cyc.eq(1),
                bare_port.stb.eq(1),
                bare_port.adr.eq(self.x_addr[2:]),
                bare_port.sel.eq(self.x_mask),
                bare_port.we.eq(self.x_store),
                bare_port.dat_w.eq(self.x_store_data)
            ]

        with m.If(self.dbus.cyc & self.dbus.err):
            m.d.sync += [
                self.m_load_error.eq(~self.dbus.we),
                self.m_store_error.eq(self.dbus.we),
                self.m_badaddr.eq(self.dbus.adr)
            ]
        with m.Elif(~self.m_stall):
            m.d.sync += [self.m_load_error.eq(0), self.m_store_error.eq(0)]

        with m.If(self.x_fence_i):
            m.d.comb += self.x_busy.eq(self._wrbuf.r.rdy)
        with m.Elif(x_dcache_select):
            m.d.comb += self.x_busy.eq(self.x_store & ~self._wrbuf.w.rdy)
        with m.Else():
            m.d.comb += self.x_busy.eq(bare_port.cyc)

        with m.If(self.m_flush):
            m.d.comb += self.m_busy.eq(m_dcache_select
                                       & ~self._dcache.s2_flush_ack)
        with m.Elif(self.m_load_error | self.m_store_error):
            m.d.comb += self.m_busy.eq(0)
        with m.Elif(m_dcache_select):
            m.d.comb += self.m_busy.eq(self.m_load & self._dcache.s2_miss)
        with m.Else():
            m.d.comb += self.m_busy.eq(bare_port.cyc)

        with m.If(self.m_load_error):
            m.d.comb += self.m_load_data.eq(0)
        with m.Elif(m_dcache_select):
            m.d.comb += self.m_load_data.eq(self._dcache.s2_rdata)
        with m.Else():
            m.d.comb += self.m_load_data.eq(bare_rdata)

        return m
Example #10
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.icache = self._icache

        a_icache_select = Signal()

        # Test whether the target address is inside the L1 cache region. We use a bit mask in order
        # to avoid carry chains from arithmetic comparisons. To this end, the base and limit
        # addresses of the cached region must satisfy the following constraints:
        # 1) the region size (i.e. ``limit - base``) must be a power of 2
        # 2) ``base`` must be a multiple of the region size

        def addr_between(base, limit):
            assert base in range(0, 2**30 + 1)
            assert limit in range(0, 2**30 + 1)
            assert limit >= base
            assert base % (limit - base) == 0
            addr_width = log2_int(limit - base, need_pow2=True)
            const_bits = 30 - addr_width
            if const_bits > 0:
                const_pat = "{:0{}b}".format(base >> addr_width, const_bits)
            else:
                const_pat = ""
            return "{}{}".format(const_pat, "-" * addr_width)

        icache_pattern = addr_between(self._icache.base >> 2,
                                      self._icache.limit >> 2)
        with m.If(self.a_pc[2:].matches(icache_pattern)):
            m.d.comb += a_icache_select.eq(1)

        f_icache_select = Signal()
        f_flush = Signal()

        with m.If(~self.a_stall):
            m.d.sync += [
                f_icache_select.eq(a_icache_select),
                f_flush.eq(self.a_flush),
            ]

        m.d.comb += [
            self._icache.s1_addr.eq(self.a_pc[2:]),
            self._icache.s1_stall.eq(self.a_stall),
            self._icache.s1_valid.eq(self.a_valid),
            self._icache.s2_addr.eq(self.f_pc[2:]),
            self._icache.s2_re.eq(f_icache_select),
            self._icache.s2_evict.eq(Const(0)),
            self._icache.s2_flush.eq(f_flush),
            self._icache.s2_valid.eq(self.f_valid),
        ]

        ibus_arbiter = m.submodules.ibus_arbiter = WishboneArbiter()
        m.d.comb += ibus_arbiter.bus.connect(self.ibus)

        icache_port = ibus_arbiter.port(priority=0)
        m.d.comb += [
            icache_port.cyc.eq(self._icache.bus_re),
            icache_port.stb.eq(self._icache.bus_re),
            icache_port.adr.eq(self._icache.bus_addr),
            icache_port.sel.eq(0b1111),
            icache_port.cti.eq(
                Mux(self._icache.bus_last, Cycle.END, Cycle.INCREMENT)),
            icache_port.bte.eq(Const(log2_int(self._icache.nwords) - 1)),
            self._icache.bus_valid.eq(icache_port.ack),
            self._icache.bus_error.eq(icache_port.err),
            self._icache.bus_rdata.eq(icache_port.dat_r)
        ]

        bare_port = ibus_arbiter.port(priority=1)
        bare_rdata = Signal.like(bare_port.dat_r)
        with m.If(bare_port.cyc):
            with m.If(bare_port.ack | bare_port.err | ~self.f_valid):
                m.d.sync += [
                    bare_port.cyc.eq(0),
                    bare_port.stb.eq(0),
                    bare_rdata.eq(bare_port.dat_r)
                ]
        with m.Elif(~a_icache_select & self.a_valid & ~self.a_stall):
            m.d.sync += [
                bare_port.cyc.eq(1),
                bare_port.stb.eq(1),
                bare_port.adr.eq(self.a_pc[2:])
            ]
        m.d.comb += bare_port.sel.eq(0b1111)

        m.d.comb += self.a_busy.eq(bare_port.cyc)

        with m.If(self.ibus.cyc & self.ibus.err):
            m.d.sync += [
                self.f_fetch_error.eq(1),
                self.f_badaddr.eq(self.ibus.adr)
            ]
        with m.Elif(~self.f_stall):
            m.d.sync += self.f_fetch_error.eq(0)

        with m.If(f_flush):
            m.d.comb += self.f_busy.eq(f_icache_select
                                       & ~self._icache.s2_flush_ack)
        with m.Elif(self.f_fetch_error):
            m.d.comb += self.f_busy.eq(0)
        with m.Elif(f_icache_select):
            m.d.comb += self.f_busy.eq(self._icache.s2_miss)
        with m.Else():
            m.d.comb += self.f_busy.eq(bare_port.cyc)

        with m.If(self.f_fetch_error):
            m.d.comb += self.f_instruction.eq(
                0x00000013)  # nop (addi x0, x0, 0)
        with m.Elif(f_icache_select):
            m.d.comb += self.f_instruction.eq(self._icache.s2_rdata)
        with m.Else():
            m.d.comb += self.f_instruction.eq(bare_rdata)

        return m
Example #11
0
    def __init__(self, nways, nlines, nwords, base, limit):
        if not isinstance(nlines, int):
            raise TypeError(
                "nlines must be an integer, not {!r}".format(nlines))
        if nlines == 0 or nlines & nlines - 1:
            raise ValueError(
                "nlines must be a power of 2, not {}".format(nlines))
        if nwords not in {4, 8, 16}:
            raise ValueError(
                "nwords must be 4, 8 or 16, not {!r}".format(nwords))
        if nways not in {1, 2}:
            raise ValueError("nways must be 1 or 2, not {!r}".format(nways))

        if not isinstance(base, int) or base not in range(0, 2**32):
            raise ValueError(
                "base must be an integer between {:#x} and {:#x} inclusive, not {!r}"
                .format(0, 2**32 - 1, base))
        if limit not in range(0, 2**32):
            raise ValueError(
                "limit must be an integer between {:#x} and {:#x} inclusive, not {!r}"
                .format(0, 2**32 - 1, limit))

        if base >= limit:
            raise ValueError(
                "limit {:#x} must be greater than base {:#x}".format(
                    limit, base))
        if (limit - base) & (limit - base) - 1:
            raise ValueError(
                "limit - base must be a power of 2, not {:#x}".format(limit -
                                                                      base))
        if base % (limit - base):
            raise ValueError(
                "base must be a multiple of limit - base, but {:#x} is not a multiple "
                "of {:#x}".format(base, limit - base))

        self.nways = nways
        self.nlines = nlines
        self.nwords = nwords
        self.base = base
        self.limit = limit

        offsetbits = log2_int(nwords)
        linebits = log2_int(nlines)
        tagbits = bits_for(limit) - linebits - offsetbits - 2

        self.s1_addr = Record([("offset", offsetbits), ("line", linebits),
                               ("tag", tagbits)])
        self.s1_stall = Signal()
        self.s1_valid = Signal()
        self.s2_addr = Record.like(self.s1_addr)
        self.s2_re = Signal()
        self.s2_flush = Signal()
        self.s2_evict = Signal()
        self.s2_valid = Signal()
        self.bus_valid = Signal()
        self.bus_error = Signal()
        self.bus_rdata = Signal(32)

        self.s2_miss = Signal()
        self.s2_flush_ack = Signal()
        self.s2_rdata = Signal(32)
        self.bus_re = Signal()
        self.bus_addr = Record.like(self.s1_addr)
        self.bus_last = Signal()