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.
This commit is contained in:
Florent Kermarrec 2020-08-05 08:56:35 +02:00
parent ee7a7f4693
commit 00629c45b0
4 changed files with 39 additions and 12 deletions

View File

@ -479,9 +479,10 @@ class SoCCSRHandler(SoCLocHandler):
supported_address_width = [14+i for i in range(4)] supported_address_width = [14+i for i in range(4)]
supported_alignment = [32] supported_alignment = [32]
supported_paging = [0x800*2**i for i in range(4)] supported_paging = [0x800*2**i for i in range(4)]
supported_ordering = ["big", "little"]
# Creation ------------------------------------------------------------------------------------- # 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) SoCLocHandler.__init__(self, "CSR", n_locs=alignment//8*(2**address_width)//paging)
self.logger = logging.getLogger("SoCCSRHandler") self.logger = logging.getLogger("SoCCSRHandler")
self.logger.info("Creating CSR Handler...") 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)))) colorer(", ".join("0x{:x}".format(x) for x in self.supported_paging))))
raise 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 # Create CSR Handler
self.data_width = data_width self.data_width = data_width
self.address_width = address_width self.address_width = address_width
self.alignment = alignment self.alignment = alignment
self.paging = paging self.paging = paging
self.ordering = ordering
self.masters = {} self.masters = {}
self.regions = {} 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.data_width),
colorer(self.alignment), colorer(self.alignment),
colorer(2**self.address_width/2**10), colorer(2**self.address_width/2**10),
colorer(self.paging), colorer(self.paging),
colorer(self.ordering),
colorer(self.n_locs))) colorer(self.n_locs)))
# Adding reserved CSRs # Adding reserved CSRs
@ -586,11 +597,12 @@ class SoCCSRHandler(SoCLocHandler):
# Str ------------------------------------------------------------------------------------------ # Str ------------------------------------------------------------------------------------------
def __str__(self): 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.data_width),
colorer(self.alignment), colorer(self.alignment),
colorer(2**self.address_width/2**10), colorer(2**self.address_width/2**10),
colorer(self.paging), colorer(self.paging),
colorer(self.ordering),
colorer(self.n_locs)) colorer(self.n_locs))
r += SoCLocHandler.__str__(self) r += SoCLocHandler.__str__(self)
r = r[:-1] r = r[:-1]
@ -678,6 +690,7 @@ class SoC(Module):
csr_data_width = 32, csr_data_width = 32,
csr_address_width = 14, csr_address_width = 14,
csr_paging = 0x800, csr_paging = 0x800,
csr_ordering = "big",
csr_reserved_csrs = {}, csr_reserved_csrs = {},
irq_n_irqs = 32, irq_n_irqs = 32,
@ -718,6 +731,7 @@ class SoC(Module):
address_width = csr_address_width, address_width = csr_address_width,
alignment = 32, alignment = 32,
paging = csr_paging, paging = csr_paging,
ordering = csr_ordering,
reserved_csrs = csr_reserved_csrs, reserved_csrs = csr_reserved_csrs,
) )
@ -947,6 +961,7 @@ class SoC(Module):
address_width = self.csr.address_width, address_width = self.csr.address_width,
alignment = self.csr.alignment, alignment = self.csr.alignment,
paging = self.csr.paging, paging = self.csr.paging,
ordering = self.csr.ordering,
soc_bus_data_width = self.bus.data_width) soc_bus_data_width = self.bus.data_width)
if len(self.csr.masters): if len(self.csr.masters):
self.submodules.csr_interconnect = csr_bus.InterconnectShared( self.submodules.csr_interconnect = csr_bus.InterconnectShared(

View File

@ -84,6 +84,7 @@ class SoCCore(LiteXSoC):
csr_data_width = 8, csr_data_width = 8,
csr_address_width = 14, csr_address_width = 14,
csr_paging = 0x800, csr_paging = 0x800,
csr_ordering = "big",
# Identifier parameters # Identifier parameters
ident = "", ident = "",
ident_version = False, ident_version = False,
@ -111,6 +112,7 @@ class SoCCore(LiteXSoC):
csr_data_width = csr_data_width, csr_data_width = csr_data_width,
csr_address_width = csr_address_width, csr_address_width = csr_address_width,
csr_paging = csr_paging, csr_paging = csr_paging,
csr_ordering = csr_ordering,
csr_reserved_csrs = self.csr_map, csr_reserved_csrs = self.csr_map,
irq_n_irqs = 32, irq_n_irqs = 32,
@ -289,6 +291,9 @@ def soc_core_args(parser):
help="CSR bus address-width") help="CSR bus address-width")
parser.add_argument("--csr-paging", default=0x800, type=auto_int, parser.add_argument("--csr-paging", default=0x800, type=auto_int,
help="CSR bus paging") help="CSR bus paging")
parser.add_argument("--csr-ordering", default="big",
help="CSR registers ordering (default=big)")
# Identifier parameters # Identifier parameters
parser.add_argument("--ident", default=None, type=str, parser.add_argument("--ident", default=None, type=str,
help="SoC identifier (default=\"\"") help="SoC identifier (default=\"\"")

View File

@ -295,9 +295,9 @@ class CSRStatus(_CompoundCSR):
for field in fields: for field in fields:
self.comb += self.status[field.offset:field.offset + field.size].eq(getattr(self.fields, field.name)) 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 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) nbits = min(self.size - i*busword, busword)
sc = CSR(nbits, self.name + str(i) if nwords > 1 else self.name) 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]) self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits])
@ -384,11 +384,11 @@ class CSRStorage(_CompoundCSR):
else: else:
self.comb += field_assign self.comb += field_assign
def do_finalize(self, busword): def do_finalize(self, busword, ordering):
nwords = (self.size + busword - 1)//busword nwords = (self.size + busword - 1)//busword
if nwords > 1 and self.atomic_write: if nwords > 1 and self.atomic_write:
backstore = Signal(self.size - busword, name=self.name + "_backstore") 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) nbits = min(self.size - i*busword, busword)
sc = CSR(nbits, self.name + str(i) if nwords else self.name) sc = CSR(nbits, self.name + str(i) if nwords else self.name)
self.simple_csrs.append(sc) self.simple_csrs.append(sc)
@ -479,7 +479,8 @@ class AutoCSR:
class GenericBank(Module): 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 # Turn description into simple CSRs and claim ownership of compound CSR modules
self.simple_csrs = [] self.simple_csrs = []
for c in description: for c in description:
@ -487,7 +488,7 @@ class GenericBank(Module):
assert c.size <= busword assert c.size <= busword
self.simple_csrs.append(c) self.simple_csrs.append(c)
else: else:
c.finalize(busword) c.finalize(busword, ordering)
self.simple_csrs += c.get_simple_csrs() self.simple_csrs += c.get_simple_csrs()
self.submodules += c self.submodules += c
self.decode_bits = bits_for(len(self.simple_csrs)-1) self.decode_bits = bits_for(len(self.simple_csrs)-1)

View File

@ -163,7 +163,7 @@ class SRAM(Module):
# CSR Bank ----------------------------------------------------------------------------------------- # CSR Bank -----------------------------------------------------------------------------------------
class CSRBank(csr.GenericBank): 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: if bus is None:
bus = Interface() bus = Interface()
self.bus = bus 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() sel = Signal()
self.comb += sel.eq(self.bus.adr[log2_int(aligned_paging):] == address) 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 # address_map is called exactly once for each object at each call to
# scan(), so it can have side effects. # scan(), so it can have side effects.
class CSRBankArray(Module): 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.source = source
self.address_map = address_map self.address_map = address_map
self.paging = paging self.paging = paging
self.ordering = ordering
self.soc_bus_data_width = soc_bus_data_width self.soc_bus_data_width = soc_bus_data_width
self.scan(ifargs, ifkwargs) self.scan(ifargs, ifkwargs)
@ -246,6 +251,7 @@ class CSRBankArray(Module):
rmap = CSRBank(csrs, mapaddr, rmap = CSRBank(csrs, mapaddr,
bus = bank_bus, bus = bank_bus,
paging = self.paging, paging = self.paging,
ordering = self.ordering,
soc_bus_data_width = self.soc_bus_data_width) soc_bus_data_width = self.soc_bus_data_width)
self.submodules += rmap self.submodules += rmap
self.banks.append((name, csrs, mapaddr, rmap)) self.banks.append((name, csrs, mapaddr, rmap))