interconnect/csr: add CSR registers ordering support.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 5 Aug 2020 06:56:35 +0000 (08:56 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 5 Aug 2020 06:57:19 +0000 (08:57 +0200)
The original CSR registers ordering (big: MSB on lower addresses) is not convenient
when the SoC is interfaced with a real OS (for example as a PCIe add-on board or
with a CPU running Linux).

With this, the original ordering is kept as default (big), but it can now be switched
to little to avoid software workarounds in drivers and should probably be in the future
the default for PCIe/Linux SoCs.

litex/soc/integration/soc.py
litex/soc/integration/soc_core.py
litex/soc/interconnect/csr.py
litex/soc/interconnect/csr_bus.py

index feff41c75b7aa480be6a0012ec2fbe38f464dbb0..480b67e3142063d7fe4e260c95d116c02e457e76 100644 (file)
@@ -479,9 +479,10 @@ class SoCCSRHandler(SoCLocHandler):
     supported_address_width = [14+i for i in range(4)]
     supported_alignment     = [32]
     supported_paging        = [0x800*2**i for i in range(4)]
+    supported_ordering      = ["big", "little"]
 
     # Creation -------------------------------------------------------------------------------------
-    def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, reserved_csrs={}):
+    def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, ordering="big", reserved_csrs={}):
         SoCLocHandler.__init__(self, "CSR", n_locs=alignment//8*(2**address_width)//paging)
         self.logger = logging.getLogger("SoCCSRHandler")
         self.logger.info("Creating CSR Handler...")
@@ -524,18 +525,28 @@ class SoCCSRHandler(SoCLocHandler):
                 colorer(", ".join("0x{:x}".format(x) for x in self.supported_paging))))
             raise
 
+        # Check Ordering
+        if ordering not in self.supported_ordering:
+            self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
+                colorer("Ordering", color="red"),
+                colorer("{}".format(paging)),
+                colorer(", ".join("{}".format(x) for x in self.supported_ordering))))
+            raise
+
         # Create CSR Handler
         self.data_width    = data_width
         self.address_width = address_width
         self.alignment     = alignment
         self.paging        = paging
+        self.ordering      = ordering
         self.masters       = {}
         self.regions       = {}
-        self.logger.info("{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging (Up to {} Locations).".format(
+        self.logger.info("{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging, {} Ordering (Up to {} Locations).".format(
             colorer(self.data_width),
             colorer(self.alignment),
             colorer(2**self.address_width/2**10),
             colorer(self.paging),
+            colorer(self.ordering),
             colorer(self.n_locs)))
 
         # Adding reserved CSRs
@@ -586,11 +597,12 @@ class SoCCSRHandler(SoCLocHandler):
 
     # Str ------------------------------------------------------------------------------------------
     def __str__(self):
-        r = "{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging (Up to {} Locations).\n".format(
+        r = "{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging, {} Ordering (Up to {} Locations).\n".format(
             colorer(self.data_width),
             colorer(self.alignment),
             colorer(2**self.address_width/2**10),
             colorer(self.paging),
+            colorer(self.ordering),
             colorer(self.n_locs))
         r += SoCLocHandler.__str__(self)
         r = r[:-1]
@@ -678,6 +690,7 @@ class SoC(Module):
         csr_data_width       = 32,
         csr_address_width    = 14,
         csr_paging           = 0x800,
+        csr_ordering         = "big",
         csr_reserved_csrs    = {},
 
         irq_n_irqs           = 32,
@@ -718,6 +731,7 @@ class SoC(Module):
             address_width = csr_address_width,
             alignment     = 32,
             paging        = csr_paging,
+            ordering      = csr_ordering,
             reserved_csrs = csr_reserved_csrs,
         )
 
@@ -947,6 +961,7 @@ class SoC(Module):
             address_width      = self.csr.address_width,
             alignment          = self.csr.alignment,
             paging             = self.csr.paging,
+            ordering           = self.csr.ordering,
             soc_bus_data_width = self.bus.data_width)
         if len(self.csr.masters):
             self.submodules.csr_interconnect = csr_bus.InterconnectShared(
index 6fff7704760a4242ecb58a48cda5fb6a506fc91d..281f34e4e12723d054e6a2fae2aa3e525774ab2b 100644 (file)
@@ -84,6 +84,7 @@ class SoCCore(LiteXSoC):
         csr_data_width           = 8,
         csr_address_width        = 14,
         csr_paging               = 0x800,
+        csr_ordering             = "big",
         # Identifier parameters
         ident                    = "",
         ident_version            = False,
@@ -111,6 +112,7 @@ class SoCCore(LiteXSoC):
             csr_data_width       = csr_data_width,
             csr_address_width    = csr_address_width,
             csr_paging           = csr_paging,
+            csr_ordering         = csr_ordering,
             csr_reserved_csrs    = self.csr_map,
 
             irq_n_irqs           = 32,
@@ -289,6 +291,9 @@ def soc_core_args(parser):
                         help="CSR bus address-width")
     parser.add_argument("--csr-paging", default=0x800, type=auto_int,
                         help="CSR bus paging")
+    parser.add_argument("--csr-ordering", default="big",
+                        help="CSR registers ordering (default=big)")
+
     # Identifier parameters
     parser.add_argument("--ident", default=None, type=str,
                         help="SoC identifier (default=\"\"")
index 9922117fd503c7f4342e9a767185ac8de0077cd7..fbc66d84a4f01c83165fcb4274a0976d0b1d1a4c 100644 (file)
@@ -295,9 +295,9 @@ class CSRStatus(_CompoundCSR):
         for field in fields:
             self.comb += self.status[field.offset:field.offset + field.size].eq(getattr(self.fields, field.name))
 
-    def do_finalize(self, busword):
+    def do_finalize(self, busword, ordering):
         nwords = (self.size + busword - 1)//busword
-        for i in reversed(range(nwords)):
+        for i in reversed(range(nwords)) if ordering == "big" else range(nwords):
             nbits = min(self.size - i*busword, busword)
             sc    = CSR(nbits, self.name + str(i) if nwords > 1 else self.name)
             self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits])
@@ -384,11 +384,11 @@ class CSRStorage(_CompoundCSR):
             else:
                 self.comb += field_assign
 
-    def do_finalize(self, busword):
+    def do_finalize(self, busword, ordering):
         nwords = (self.size + busword - 1)//busword
         if nwords > 1 and self.atomic_write:
             backstore = Signal(self.size - busword, name=self.name + "_backstore")
-        for i in reversed(range(nwords)):
+        for i in reversed(range(nwords)) if ordering == "big" else range(nwords):
             nbits = min(self.size - i*busword, busword)
             sc    = CSR(nbits, self.name + str(i) if nwords else self.name)
             self.simple_csrs.append(sc)
@@ -479,7 +479,8 @@ class AutoCSR:
 
 
 class GenericBank(Module):
-    def __init__(self, description, busword):
+    def __init__(self, description, busword, ordering="big"):
+        assert ordering in ["big", "little"]
         # Turn description into simple CSRs and claim ownership of compound CSR modules
         self.simple_csrs = []
         for c in description:
@@ -487,7 +488,7 @@ class GenericBank(Module):
                 assert c.size <= busword
                 self.simple_csrs.append(c)
             else:
-                c.finalize(busword)
+                c.finalize(busword, ordering)
                 self.simple_csrs += c.get_simple_csrs()
                 self.submodules  += c
         self.decode_bits = bits_for(len(self.simple_csrs)-1)
index cded5ae29f23c6e6784b198d525e2474115d9c11..c09bfe5d3e0b9f0eb836261e7e55ce6f06584a18 100644 (file)
@@ -163,7 +163,7 @@ class SRAM(Module):
 # CSR Bank -----------------------------------------------------------------------------------------
 
 class CSRBank(csr.GenericBank):
-    def __init__(self, description, address=0, bus=None, paging=0x800, soc_bus_data_width=32):
+    def __init__(self, description, address=0, bus=None, paging=0x800, ordering="big", soc_bus_data_width=32):
         if bus is None:
             bus = Interface()
         self.bus = bus
@@ -171,7 +171,11 @@ class CSRBank(csr.GenericBank):
 
         # # #
 
-        csr.GenericBank.__init__(self, description, len(self.bus.dat_w))
+        csr.GenericBank.__init__(self,
+            description = description,
+            busword     = len(self.bus.dat_w),
+            ordering    = ordering,
+        )
 
         sel = Signal()
         self.comb += sel.eq(self.bus.adr[log2_int(aligned_paging):] == address)
@@ -201,10 +205,11 @@ class CSRBank(csr.GenericBank):
 # address_map is called exactly once for each object at each call to
 # scan(), so it can have side effects.
 class CSRBankArray(Module):
-    def __init__(self, source, address_map, *ifargs, paging=0x800, soc_bus_data_width=32, **ifkwargs):
+    def __init__(self, source, address_map, *ifargs, paging=0x800, ordering="big", soc_bus_data_width=32, **ifkwargs):
         self.source             = source
         self.address_map        = address_map
         self.paging             = paging
+        self.ordering           = ordering
         self.soc_bus_data_width = soc_bus_data_width
         self.scan(ifargs, ifkwargs)
 
@@ -246,6 +251,7 @@ class CSRBankArray(Module):
                 rmap = CSRBank(csrs, mapaddr,
                     bus                = bank_bus,
                     paging             = self.paging,
+                    ordering           = self.ordering,
                     soc_bus_data_width = self.soc_bus_data_width)
                 self.submodules += rmap
                 self.banks.append((name, csrs, mapaddr, rmap))