From 00629c45b0ecb44149893439d040d4b4267ba4ea Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 5 Aug 2020 08:56:35 +0200 Subject: [PATCH] interconnect/csr: add CSR registers ordering support. 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 | 21 ++++++++++++++++++--- litex/soc/integration/soc_core.py | 5 +++++ litex/soc/interconnect/csr.py | 13 +++++++------ litex/soc/interconnect/csr_bus.py | 12 +++++++++--- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index feff41c75..480b67e31 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -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( diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 6fff77047..281f34e4e 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -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=\"\"") diff --git a/litex/soc/interconnect/csr.py b/litex/soc/interconnect/csr.py index 9922117fd..fbc66d84a 100644 --- a/litex/soc/interconnect/csr.py +++ b/litex/soc/interconnect/csr.py @@ -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) diff --git a/litex/soc/interconnect/csr_bus.py b/litex/soc/interconnect/csr_bus.py index cded5ae29..c09bfe5d3 100644 --- a/litex/soc/interconnect/csr_bus.py +++ b/litex/soc/interconnect/csr_bus.py @@ -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))