core/cpu: integrate Zynq as a classical CPU (Zynq7000), deprecate SoCZynq.
[litex.git] / litex / soc / integration / soc.py
index d52402c956aaa083f7fe67f9872d86c9f3f7f2c7..20025383ce894e36d7b6ca71be6adefb88b5223a 100644 (file)
@@ -101,13 +101,13 @@ class SoCCSRRegion:
 # SoCBusHandler ------------------------------------------------------------------------------------
 
 class SoCBusHandler(Module):
-    supported_standard      = ["wishbone"]
+    supported_standard      = ["wishbone", "axi-lite"]
     supported_data_width    = [32, 64]
     supported_address_width = [32]
 
     # Creation -------------------------------------------------------------------------------------
-    def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
-        self.logger = logging.getLogger("SoCBusHandler")
+    def __init__(self, name="SoCBusHandler", standard="wishbone", data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
+        self.logger = logging.getLogger(name)
         self.logger.info("Creating Bus Handler...")
 
         # Check Standard
@@ -130,7 +130,7 @@ class SoCBusHandler(Module):
         if address_width not in self.supported_address_width:
             self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
                 colorer("Address Width", color="red"),
-                colorer(data_width),
+                colorer(address_width),
                 colorer(", ".join(str(x) for x in self.supported_address_width))))
             raise
 
@@ -281,45 +281,57 @@ class SoCBusHandler(Module):
     def add_adapter(self, name, interface, direction="m2s"):
         assert direction in ["m2s", "s2m"]
 
-        if isinstance(interface, wishbone.Interface):
-            new_interface = wishbone.Interface(data_width=self.data_width)
-            if direction == "m2s":
-                converter = wishbone.Converter(master=interface, slave=new_interface)
-            if direction == "s2m":
-                converter = wishbone.Converter(master=new_interface, slave=interface)
-            self.submodules += converter
-        elif isinstance(interface, axi.AXILiteInterface):
-            # Data width conversion
-            intermediate = axi.AXILiteInterface(data_width=self.data_width)
+        # Data width conversion
+        if interface.data_width != self.data_width:
+            interface_cls = type(interface)
+            converter_cls = {
+                wishbone.Interface:   wishbone.Converter,
+                axi.AXILiteInterface: axi.AXILiteConverter,
+            }[interface_cls]
+            converted_interface = interface_cls(data_width=self.data_width)
             if direction == "m2s":
-                converter = axi.AXILiteConverter(master=interface, slave=intermediate)
-            if direction == "s2m":
-                converter = axi.AXILiteConverter(master=intermediate, slave=interface)
-            self.submodules += converter
-            # Bus type conversion
-            new_interface = wishbone.Interface(data_width=self.data_width)
-            if direction == "m2s":
-                converter = axi.AXILite2Wishbone(axi_lite=intermediate, wishbone=new_interface)
+                master, slave = interface, converted_interface
             elif direction == "s2m":
-                converter = axi.Wishbone2AXILite(wishbone=new_interface, axi_lite=intermediate)
+                master, slave = converted_interface, interface
+            converter = converter_cls(master=master, slave=slave)
             self.submodules += converter
         else:
-            raise TypeError(interface)
-
-        fmt = "{name} Bus {converted} from {frombus} {frombits}-bit to {tobus} {tobits}-bit."
-        frombus  = "Wishbone" if isinstance(interface, wishbone.Interface) else "AXILite"
-        tobus    = "Wishbone" if isinstance(new_interface, wishbone.Interface) else "AXILite"
-        frombits = interface.data_width
-        tobits   = new_interface.data_width
-        if frombus != tobus or frombits != tobits:
+            converted_interface = interface
+
+        # Wishbone <-> AXILite bridging
+        main_bus_cls = {
+            "wishbone": wishbone.Interface,
+            "axi-lite": axi.AXILiteInterface,
+        }[self.standard]
+        if isinstance(converted_interface, main_bus_cls):
+            bridged_interface = converted_interface
+        else:
+            bridged_interface = main_bus_cls(data_width=self.data_width)
+            if direction == "m2s":
+                master, slave = converted_interface, bridged_interface
+            elif direction == "s2m":
+                master, slave = bridged_interface, converted_interface
+            bridge_cls = {
+                (wishbone.Interface, axi.AXILiteInterface): axi.Wishbone2AXILite,
+                (axi.AXILiteInterface, wishbone.Interface): axi.AXILite2Wishbone,
+            }[type(master), type(slave)]
+            bridge = bridge_cls(master, slave)
+            self.submodules += bridge
+
+        if type(interface) != type(bridged_interface) or interface.data_width != bridged_interface.data_width:
+            fmt = "{name} Bus {converted} from {frombus} {frombits}-bit to {tobus} {tobits}-bit."
+            bus_names = {
+                wishbone.Interface:   "Wishbone",
+                axi.AXILiteInterface: "AXI Lite",
+            }
             self.logger.info(fmt.format(
                 name      = colorer(name),
                 converted = colorer("converted", color="cyan"),
-                frombus   = colorer("Wishbone" if isinstance(interface, wishbone.Interface) else "AXILite"),
+                frombus   = colorer(bus_names[type(interface)]),
                 frombits  = colorer(interface.data_width),
-                tobus     = colorer("Wishbone" if isinstance(new_interface, wishbone.Interface) else "AXILite"),
-                tobits    = colorer(new_interface.data_width)))
-        return new_interface
+                tobus     = colorer(bus_names[type(bridged_interface)]),
+                tobits    = colorer(bridged_interface.data_width)))
+        return bridged_interface
 
     def add_master(self, name=None, master=None):
         if name is None:
@@ -753,37 +765,41 @@ class SoC(Module):
         setattr(self.submodules, name, SoCController(**kwargs))
         self.csr.add(name, use_loc_if_exists=True)
 
-    def add_ram(self, name, origin, size, contents=[], mode="rw", bus=None):
-        if bus is None:
-            bus = wishbone.Interface(data_width=self.bus.data_width)
-
-        if isinstance(bus, wishbone.Interface):
-            ram = wishbone.SRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
-        elif isinstance(bus, axi.AXILiteInterface):
-            ram = axi.AXILiteSRAM(size, bus=bus, init=contents, read_only=(mode == "r"))
-        else:
-            raise TypeError(bus)
-
+    def add_ram(self, name, origin, size, contents=[], mode="rw"):
+        ram_cls = {
+            "wishbone": wishbone.SRAM,
+            "axi-lite": axi.AXILiteSRAM,
+        }[self.bus.standard]
+        interface_cls = {
+            "wishbone": wishbone.Interface,
+            "axi-lite": axi.AXILiteInterface,
+        }[self.bus.standard]
+        ram_bus = interface_cls(data_width=self.bus.data_width)
+        ram     = ram_cls(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
         self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
         self.check_if_exists(name)
-        self.logger.info("{} RAM {} {} {}.".format(
-            colorer("Wishbone" if isinstance(bus, wishbone.Interface) else "AXILite"),
+        self.logger.info("RAM {} {} {}.".format(
             colorer(name),
             colorer("added", color="green"),
             self.bus.regions[name]))
         setattr(self.submodules, name, ram)
 
-    def add_rom(self, name, origin, size, contents=[], bus=None):
-        self.add_ram(name, origin, size, contents, mode="r", bus=bus)
+    def add_rom(self, name, origin, size, contents=[]):
+        self.add_ram(name, origin, size, contents, mode="r")
 
     def add_csr_bridge(self, origin):
-        self.submodules.csr_bridge = wishbone.Wishbone2CSR(
+        csr_bridge_cls = {
+            "wishbone": wishbone.Wishbone2CSR,
+            "axi-lite": axi.AXILite2CSR,
+        }[self.bus.standard]
+        self.submodules.csr_bridge = csr_bridge_cls(
             bus_csr       = csr_bus.Interface(
             address_width = self.csr.address_width,
             data_width    = self.csr.data_width))
         csr_size   = 2**(self.csr.address_width + 2)
         csr_region = SoCRegion(origin=origin, size=csr_size, cached=False)
-        self.bus.add_slave("csr", self.csr_bridge.wishbone, csr_region)
+        bus = getattr(self.csr_bridge, self.bus.standard.replace('-', '_'))
+        self.bus.add_slave("csr", bus, csr_region)
         self.csr.add_master(name="bridge", master=self.csr_bridge.csr)
         self.add_config("CSR_DATA_WIDTH", self.csr.data_width)
         self.add_config("CSR_ALIGNMENT",  self.csr.alignment)
@@ -809,7 +825,7 @@ class SoC(Module):
             self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
         self.mem_map.update(self.cpu.mem_map) # FIXME
         # Add Bus Masters/CSR/IRQs
-        if not isinstance(self.cpu, cpu.CPUNone):
+        if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
             if reset_address is None:
                 reset_address = self.mem_map["rom"]
             self.cpu.set_reset_address(reset_address)
@@ -821,7 +837,18 @@ class SoC(Module):
                     self.irq.add(name, loc)
                 self.add_config("CPU_HAS_INTERRUPT")
 
+            # Create optional DMA Bus (for Cache Coherence)
+            if hasattr(self.cpu, "dma_bus"):
+                self.submodules.dma_bus = SoCBusHandler(
+                    name             = "SoCDMABusHandler",
+                    standard         = "wishbone",
+                    data_width       = self.bus.data_width,
+                )
+                dma_bus = wishbone.Interface(data_width=self.bus.data_width)
+                self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x80000000)) # FIXME: size
+                self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus)
 
+            # Connect SoCController's reset to CPU reset
             if hasattr(self, "ctrl"):
                 if hasattr(self.ctrl, "reset"):
                     self.comb += self.cpu.reset.eq(self.ctrl.reset)
@@ -846,22 +873,33 @@ class SoC(Module):
         self.logger.info(colorer("Finalized SoC:"))
         self.logger.info(colorer("-"*80, color="bright"))
         self.logger.info(self.bus)
+        if hasattr(self, "dma_bus"):
+            self.logger.info(self.dma_bus)
         self.logger.info(self.csr)
         self.logger.info(self.irq)
         self.logger.info(colorer("-"*80, color="bright"))
 
+        interconnect_p2p_cls = {
+            "wishbone": wishbone.InterconnectPointToPoint,
+            "axi-lite": axi.AXILiteInterconnectPointToPoint,
+        }[self.bus.standard]
+        interconnect_shared_cls = {
+            "wishbone": wishbone.InterconnectShared,
+            "axi-lite": axi.AXILiteInterconnectShared,
+        }[self.bus.standard]
+
         # SoC Bus Interconnect ---------------------------------------------------------------------
         if len(self.bus.masters) and len(self.bus.slaves):
             # If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
             if ((len(self.bus.masters) == 1)  and
                 (len(self.bus.slaves)  == 1)  and
                 (next(iter(self.bus.regions.values())).origin == 0)):
-                self.submodules.bus_interconnect = wishbone.InterconnectPointToPoint(
+                self.submodules.bus_interconnect = interconnect_p2p_cls(
                     master = next(iter(self.bus.masters.values())),
                     slave  = next(iter(self.bus.slaves.values())))
             # Otherwise, use InterconnectShared.
             else:
-                self.submodules.bus_interconnect = wishbone.InterconnectShared(
+                self.submodules.bus_interconnect = interconnect_shared_cls(
                     masters        = self.bus.masters.values(),
                     slaves         = [(self.bus.regions[n].decoder(self.bus), s) for n, s in self.bus.slaves.items()],
                     register       = True,
@@ -877,6 +915,28 @@ class SoC(Module):
         self.add_constant("CONFIG_BUS_DATA_WIDTH",    self.bus.data_width)
         self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_width)
 
+        # SoC DMA Bus Interconnect (Cache Coherence) -----------------------------------------------
+        if hasattr(self, "dma_bus"):
+            if len(self.dma_bus.masters) and len(self.dma_bus.slaves):
+                # If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
+                if ((len(self.dma_bus.masters) == 1)  and
+                    (len(self.dma_bus.slaves)  == 1)  and
+                    (next(iter(self.dma_bus.regions.values())).origin == 0)):
+                    self.submodules.bus_interconnect = wishbone.InterconnectPointToPoint(
+                        master = next(iter(self.dma_bus.masters.values())),
+                        slave  = next(iter(self.dma_bus.slaves.values())))
+                # Otherwise, use InterconnectShared.
+                else:
+                    self.submodules.dma_bus_interconnect = wishbone.InterconnectShared(
+                        masters        = self.dma_bus.masters.values(),
+                        slaves         = [(self.dma_bus.regions[n].decoder(self.dma_bus), s) for n, s in self.dma_bus.slaves.items()],
+                        register       = True)
+            self.bus.logger.info("DMA Interconnect: {} ({} <-> {}).".format(
+                colorer(self.dma_bus_interconnect.__class__.__name__),
+                colorer(len(self.dma_bus.masters)),
+                colorer(len(self.dma_bus.slaves))))
+            self.add_constant("CONFIG_CPU_HAS_DMA_BUS")
+
         # SoC CSR Interconnect ---------------------------------------------------------------------
         self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
             address_map        = self.csr.address_map,
@@ -912,7 +972,7 @@ class SoC(Module):
             self.add_constant(name + "_" + constant.name, constant.value.value)
 
         # SoC CPU Check ----------------------------------------------------------------------------
-        if not isinstance(self.cpu, cpu.CPUNone):
+        if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
             if "sram" not in self.bus.regions.keys():
                 self.logger.error("CPU needs {} Region to be {} as Bus or Linker Region.".format(
                     colorer("sram"),
@@ -1272,7 +1332,7 @@ class LiteXSoC(SoC):
         pads = self.platform.request(name)
         if hasattr(pads, "rst"):
             self.comb += pads.rst.eq(0)
-        spisdcard = SPIMaster(pads, 32, self.sys_clk_freq, spi_clk_freq, mode="aligned")
+        spisdcard = SPIMaster(pads, 8, self.sys_clk_freq, spi_clk_freq)
         spisdcard.add_clk_divider()
         setattr(self.submodules, name, spisdcard)
         self.add_csr(name)
@@ -1305,7 +1365,8 @@ class LiteXSoC(SoC):
             bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
             self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
             self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
-            self.bus.add_master("sdblock2mem", master=bus)
+            dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+            dma_bus.add_master("sdblock2mem", master=bus)
             self.add_csr("sdblock2mem")
 
         # Mem2Block DMA
@@ -1313,5 +1374,6 @@ class LiteXSoC(SoC):
             bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
             self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
             self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
-            self.bus.add_master("sdmem2block", master=bus)
+            dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+            dma_bus.add_master("sdmem2block", master=bus)
             self.add_csr("sdmem2block")