From bd7921cda80f46b60f0a6b65b534c03d0a758d78 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 13 Feb 2024 15:59:42 +0100 Subject: [PATCH] soc/add_master: Add region support to allow remapping. Allow connecting a master to a specific region of the SoC and limiting access to it. --- litex/soc/integration/soc.py | 33 ++++++++++++++++++++++++-- litex/soc/interconnect/axi/axi_full.py | 14 +++++++++++ litex/soc/interconnect/axi/axi_lite.py | 15 ++++++++++++ litex/soc/interconnect/wishbone.py | 18 ++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index c1b063c94..2a65d4076 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -447,7 +447,34 @@ class SoCBusHandler(LiteXModule): return adapted_interface - def add_master(self, name=None, master=None): + # Add Remapper --------------------------------------------------------------------------------- + def add_remapper(self, name, interface, origin, size): + interface_cls = type(interface) + remapper_cls = { + wishbone.Interface : wishbone.Remapper, + axi.AXILiteInterface : axi.AXILiteRemapper, + axi.AXIInterface : axi.AXIRemapper, + }[interface_cls] + + adapted_interface = interface_cls( + data_width = interface.data_width, + address_width = interface.address_width, + addressing = interface.addressing, + ) + + self.submodules += remapper_cls(interface, adapted_interface, origin, size) + + fmt = "{name} Bus {remapped} to {origin} (Size: {size})." + self.logger.info(fmt.format( + name = colorer(name), + remapped = colorer("remapped", color="cyan"), + origin = colorer(f"0x{origin:08x}"), + size = colorer(f"0x{size:08x}"), + )) + + return adapted_interface + + def add_master(self, name=None, master=None, region=None): if name is None: name = "master{:d}".format(len(self.masters)) if name in self.masters.keys(): @@ -456,6 +483,8 @@ class SoCBusHandler(LiteXModule): colorer("already declared", color="red"))) self.logger.error(self) raise SoCError() + if region: + master = self.add_remapper(name, master, region.origin, region.size) master = self.add_adapter(name, master, "m2s") self.masters[name] = master self.logger.info("{} {} as Bus Master.".format( @@ -466,7 +495,7 @@ class SoCBusHandler(LiteXModule): self.add_master(self, name=name, master=controller) def add_slave(self, name=None, slave=None, region=None): - no_name = name is None + no_name = name is None no_region = region is None if no_name and no_region: self.logger.error("Please {} {} or/and {} of Bus Slave.".format( diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index dd7303878..f74171511 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -7,6 +7,8 @@ """AXI4-Full/Lite support for LiteX""" +from math import log2 + from migen import * from migen.genlib import roundrobin @@ -138,6 +140,18 @@ class AXIInterface: def layout_flat(self): return list(axi_layout_flat(self)) +# AXI Remapper ------------------------------------------------------------------------------------- + +class AXIRemapper(LiteXModule): + def __init__(self, master, slave, origin, size): + # Mask. + mask = 2**int(log2(size)) - 1 + + # Address Mask and Shift. + self.comb += master.connect(slave) + self.comb += slave.aw.addr.eq(origin | master.aw.addr & mask) + self.comb += slave.ar.addr.eq(origin | master.ar.addr & mask) + # AXI Bursts to Beats ------------------------------------------------------------------------------ class AXIBurst2Beat(LiteXModule): diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 64d514d91..1289d63c3 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -7,6 +7,8 @@ """AXI4-Full/Lite support for LiteX""" +from math import log2 + from migen import * from migen.genlib import roundrobin @@ -128,6 +130,19 @@ class AXILiteInterface: yield self.r.ready.eq(0) return (data, resp) + +# AXI-Lite Remapper -------------------------------------------------------------------------------- + +class AXILiteRemapper(LiteXModule): + def __init__(self, master, slave, origin, size): + # Mask. + mask = 2**int(log2(size)) - 1 + + # Address Mask and Shift. + self.comb += master.connect(slave) + self.comb += slave.aw.addr.eq(origin | master.aw.addr & mask) + self.comb += slave.ar.addr.eq(origin | master.ar.addr & mask) + # AXI-Lite to Simple Bus --------------------------------------------------------------------------- def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None): diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 5f3bc1417..2f7665468 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -126,6 +126,24 @@ class Interface(Record): r.append(sig.eq(pad)) return r +# Wishbone Remapper -------------------------------------------------------------------------------- + +class Remapper(LiteXModule): + def __init__(self, master, slave, origin, size): + # Parameters. + addressing = master.addressing + assert master.addressing == slave.addressing + + # Mask. + log2_size = int(log2(size)) + if addressing == "word": + log2_size -= int(log2(len(master.dat_w)//8)) + mask = 2**log2_size - 1 + + # Address Mask and Shift. + self.comb += master.connect(slave, omit={"adr"}) + self.comb += slave.adr.eq(origin | (master.adr & mask)) + # Wishbone Timeout --------------------------------------------------------------------------------- class Timeout(LiteXModule):