integration/soc: Cosmetic cleanup pass.

This commit is contained in:
Florent Kermarrec 2021-03-25 09:13:43 +01:00
parent 6e23fb1d99
commit c9ac5424f4
1 changed files with 116 additions and 105 deletions

View File

@ -75,8 +75,8 @@ class SoCRegion:
raise raise
if (origin == 0) and (size == 2**bus.address_width): if (origin == 0) and (size == 2**bus.address_width):
return lambda a : True return lambda a : True
origin >>= int(log2(bus.data_width//8)) # bytes to words aligned origin >>= int(log2(bus.data_width//8)) # bytes to words aligned.
size >>= int(log2(bus.data_width//8)) # bytes to words aligned size >>= int(log2(bus.data_width//8)) # bytes to words aligned.
return lambda a: (a[log2_int(size):] == (origin >> log2_int(size))) return lambda a: (a[log2_int(size):] == (origin >> log2_int(size)))
def __str__(self): def __str__(self):
@ -112,7 +112,7 @@ class SoCBusHandler(Module):
self.logger = logging.getLogger(name) self.logger = logging.getLogger(name)
self.logger.info("Creating Bus Handler...") self.logger.info("Creating Bus Handler...")
# Check Standard # Check Bus Standard.
if standard not in self.supported_standard: if standard not in self.supported_standard:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Bus standard", color="red"), colorer("Bus standard", color="red"),
@ -120,7 +120,7 @@ class SoCBusHandler(Module):
colorer(", ".join(self.supported_standard)))) colorer(", ".join(self.supported_standard))))
raise raise
# Check Data Width # Check Bus Data Width.
if data_width not in self.supported_data_width: if data_width not in self.supported_data_width:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Data Width", color="red"), colorer("Data Width", color="red"),
@ -128,7 +128,7 @@ class SoCBusHandler(Module):
colorer(", ".join(str(x) for x in self.supported_data_width)))) colorer(", ".join(str(x) for x in self.supported_data_width))))
raise raise
# Check Address Width # Check Bus Address Width.
if address_width not in self.supported_address_width: if address_width not in self.supported_address_width:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Address Width", color="red"), colorer("Address Width", color="red"),
@ -148,7 +148,7 @@ class SoCBusHandler(Module):
self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format( self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
colorer(data_width), colorer(standard), colorer(2**address_width/2**30))) colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
# Adding reserved regions # Add reserved regions.
self.logger.info("Adding {} Bus Regions...".format(colorer("reserved", color="cyan"))) self.logger.info("Adding {} Bus Regions...".format(colorer("reserved", color="cyan")))
for name, region in reserved_regions.items(): for name, region in reserved_regions.items():
if isinstance(region, int): if isinstance(region, int):
@ -164,9 +164,10 @@ class SoCBusHandler(Module):
self.logger.error("{} already declared as Region:".format(colorer(name, color="red"))) self.logger.error("{} already declared as Region:".format(colorer(name, color="red")))
self.logger.error(self) self.logger.error(self)
raise raise
# Check if SoCIORegion # Check if is SoCIORegion.
if isinstance(region, SoCIORegion): if isinstance(region, SoCIORegion):
self.io_regions[name] = region self.io_regions[name] = region
# Check for overlap with others IO regions.
overlap = self.check_regions_overlap(self.io_regions) overlap = self.check_regions_overlap(self.io_regions)
if overlap is not None: if overlap is not None:
self.logger.error("IO Region {} between {} and {}:".format( self.logger.error("IO Region {} between {} and {}:".format(
@ -180,15 +181,16 @@ class SoCBusHandler(Module):
colorer(name, color="underline"), colorer(name, color="underline"),
colorer("added", color="green"), colorer("added", color="green"),
str(region))) str(region)))
# Check if SoCRegion # Check if is SoCRegion
elif isinstance(region, SoCRegion): elif isinstance(region, SoCRegion):
# If no origin specified, allocate region. # If no Origin specified, allocate Region.
if region.origin is None: if region.origin is None:
allocated = True allocated = True
region = self.alloc_region(name, region.size, region.cached) region = self.alloc_region(name, region.size, region.cached)
self.regions[name] = region self.regions[name] = region
# Else add region and check for overlaps. # Else add Region.
else: else:
# If Region is an IO Region is not cached.
if not region.cached: if not region.cached:
if not self.check_region_is_io(region): if not self.check_region_is_io(region):
self.logger.error("{} Region {}: {}.".format( self.logger.error("{} Region {}: {}.".format(
@ -198,6 +200,7 @@ class SoCBusHandler(Module):
self.logger.error(self) self.logger.error(self)
raise raise
self.regions[name] = region self.regions[name] = region
# Check for overlab with others IO regions.
overlap = self.check_regions_overlap(self.regions) overlap = self.check_regions_overlap(self.regions)
if overlap is not None: if overlap is not None:
self.logger.error("Region {} between {} and {}:".format( self.logger.error("Region {} between {} and {}:".format(
@ -220,27 +223,27 @@ class SoCBusHandler(Module):
colorer("Cached" if cached else "IO"), colorer("Cached" if cached else "IO"),
colorer("0x{:08x}".format(size)))) colorer("0x{:08x}".format(size))))
# Limit Search Regions # Limit Search Regions.
if cached == False: if cached == False:
search_regions = self.io_regions search_regions = self.io_regions
else: else:
search_regions = {"main": SoCRegion(origin=0x00000000, size=2**self.address_width-1)} search_regions = {"main": SoCRegion(origin=0x00000000, size=2**self.address_width-1)}
# Iterate on Search_Regions to find a Candidate # Iterate on Search_Regions to find a Candidate.
for _, search_region in search_regions.items(): for _, search_region in search_regions.items():
origin = search_region.origin origin = search_region.origin
while (origin + size) < (search_region.origin + search_region.size_pow2): while (origin + size) < (search_region.origin + search_region.size_pow2):
# Create a Candicate. # Create a Candicate.
candidate = SoCRegion(origin=origin, size=size, cached=cached) candidate = SoCRegion(origin=origin, size=size, cached=cached)
overlap = False overlap = False
# Check Candidate does not overlap with allocated existing regions # Check Candidate does not overlap with allocated existing regions.
for _, allocated in self.regions.items(): for _, allocated in self.regions.items():
if self.check_regions_overlap({"0": allocated, "1": candidate}) is not None: if self.check_regions_overlap({"0": allocated, "1": candidate}) is not None:
origin = allocated.origin + allocated.size_pow2 origin = allocated.origin + allocated.size_pow2
overlap = True overlap = True
break break
if not overlap: if not overlap:
# If no overlap, the Candidate is selected # If no overlap, the Candidate is selected.
return candidate return candidate
self.logger.error("Not enough Address Space to allocate Region.") self.logger.error("Not enough Address Space to allocate Region.")
@ -283,7 +286,7 @@ class SoCBusHandler(Module):
def add_adapter(self, name, interface, direction="m2s"): def add_adapter(self, name, interface, direction="m2s"):
assert direction in ["m2s", "s2m"] assert direction in ["m2s", "s2m"]
# Data width conversion # Data width conversion.
if interface.data_width != self.data_width: if interface.data_width != self.data_width:
interface_cls = type(interface) interface_cls = type(interface)
converter_cls = { converter_cls = {
@ -300,7 +303,7 @@ class SoCBusHandler(Module):
else: else:
converted_interface = interface converted_interface = interface
# Wishbone <-> AXILite bridging # Wishbone <-> AXILite bridging.
main_bus_cls = { main_bus_cls = {
"wishbone": wishbone.Interface, "wishbone": wishbone.Interface,
"axi-lite": axi.AXILiteInterface, "axi-lite": axi.AXILiteInterface,
@ -321,7 +324,7 @@ class SoCBusHandler(Module):
self.submodules += bridge self.submodules += bridge
if type(interface) != type(bridged_interface) or interface.data_width != bridged_interface.data_width: 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." fmt = "{name} Bus {converted} from {from_bus} {from_bits}-bit to {to_bus} {to_bits}-bit."
bus_names = { bus_names = {
wishbone.Interface: "Wishbone", wishbone.Interface: "Wishbone",
axi.AXILiteInterface: "AXI Lite", axi.AXILiteInterface: "AXI Lite",
@ -329,10 +332,10 @@ class SoCBusHandler(Module):
self.logger.info(fmt.format( self.logger.info(fmt.format(
name = colorer(name), name = colorer(name),
converted = colorer("converted", color="cyan"), converted = colorer("converted", color="cyan"),
frombus = colorer(bus_names[type(interface)]), from_bus = colorer(bus_names[type(interface)]),
frombits = colorer(interface.data_width), from_bits = colorer(interface.data_width),
tobus = colorer(bus_names[type(bridged_interface)]), to_bus = colorer(bus_names[type(bridged_interface)]),
tobits = colorer(bridged_interface.data_width))) to_bits = colorer(bridged_interface.data_width)))
return bridged_interface return bridged_interface
def add_master(self, name=None, master=None): def add_master(self, name=None, master=None):
@ -403,7 +406,7 @@ class SoCBusHandler(Module):
r = r[:-1] r = r[:-1]
return r return r
# SoCLocHandler -------------------------------------------------------------------------------------- # SoCLocHandler ------------------------------------------------------------------------------------
class SoCLocHandler(Module): class SoCLocHandler(Module):
# Creation ------------------------------------------------------------------------------------- # Creation -------------------------------------------------------------------------------------
@ -487,7 +490,7 @@ class SoCCSRHandler(SoCLocHandler):
self.logger = logging.getLogger("SoCCSRHandler") self.logger = logging.getLogger("SoCCSRHandler")
self.logger.info("Creating CSR Handler...") self.logger.info("Creating CSR Handler...")
# Check Data Width # Check CSR Data Width.
if data_width not in self.supported_data_width: if data_width not in self.supported_data_width:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Data Width", color="red"), colorer("Data Width", color="red"),
@ -495,7 +498,7 @@ class SoCCSRHandler(SoCLocHandler):
colorer(", ".join(str(x) for x in self.supported_data_width)))) colorer(", ".join(str(x) for x in self.supported_data_width))))
raise raise
# Check Address Width # Check CSR Address Width.
if address_width not in self.supported_address_width: if address_width not in self.supported_address_width:
self.logger.error("Unsupported {} {} supporteds: {:s}".format( self.logger.error("Unsupported {} {} supporteds: {:s}".format(
colorer("Address Width", color="red"), colorer("Address Width", color="red"),
@ -503,7 +506,7 @@ class SoCCSRHandler(SoCLocHandler):
colorer(", ".join(str(x) for x in self.supported_address_width)))) colorer(", ".join(str(x) for x in self.supported_address_width))))
raise raise
# Check Alignment # Check CSR Alignment.
if alignment not in self.supported_alignment: if alignment not in self.supported_alignment:
self.logger.error("Unsupported {}: {} supporteds: {:s}".format( self.logger.error("Unsupported {}: {} supporteds: {:s}".format(
colorer("Alignment", color="red"), colorer("Alignment", color="red"),
@ -517,7 +520,7 @@ class SoCCSRHandler(SoCLocHandler):
colorer(data_width))) colorer(data_width)))
raise raise
# Check Paging # Check CSR Paging.
if paging not in self.supported_paging: if paging not in self.supported_paging:
self.logger.error("Unsupported {} 0x{}, supporteds: {:s}".format( self.logger.error("Unsupported {} 0x{}, supporteds: {:s}".format(
colorer("Paging", color="red"), colorer("Paging", color="red"),
@ -525,7 +528,7 @@ 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 # Check CSR Ordering.
if ordering not in self.supported_ordering: if ordering not in self.supported_ordering:
self.logger.error("Unsupported {} {}, supporteds: {:s}".format( self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
colorer("Ordering", color="red"), colorer("Ordering", color="red"),
@ -533,7 +536,7 @@ class SoCCSRHandler(SoCLocHandler):
colorer(", ".join("{}".format(x) for x in self.supported_ordering)))) colorer(", ".join("{}".format(x) for x in self.supported_ordering))))
raise 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
@ -549,7 +552,7 @@ class SoCCSRHandler(SoCLocHandler):
colorer(self.ordering), colorer(self.ordering),
colorer(self.n_locs))) colorer(self.n_locs)))
# Adding reserved CSRs # Add reserved CSRs.
self.logger.info("Adding {} CSRs...".format(colorer("reserved", color="cyan"))) self.logger.info("Adding {} CSRs...".format(colorer("reserved", color="cyan")))
for name, n in reserved_csrs.items(): for name, n in reserved_csrs.items():
self.add(name, n) self.add(name, n)
@ -618,16 +621,16 @@ class SoCIRQHandler(SoCLocHandler):
self.logger.info("Creating IRQ Handler...") self.logger.info("Creating IRQ Handler...")
self.enabled = False self.enabled = False
# Check IRQ Number # Check IRQ Number.
if n_irqs > 32: if n_irqs > 32:
self.logger.error("Unsupported IRQs number: {} supporteds: {:s}".format( self.logger.error("Unsupported IRQs number: {} supporteds: {:s}".format(
colorer(n_irqs, color="red"), colorer("Up to 32", color="green"))) colorer(n_irqs, color="red"), colorer("Up to 32", color="green")))
raise raise
# Create IRQ Handler # Create IRQ Handler.
self.logger.info("IRQ Handler (up to {} Locations).".format(colorer(n_irqs))) self.logger.info("IRQ Handler (up to {} Locations).".format(colorer(n_irqs)))
# Adding reserved IRQs # Adding reserved IRQs.
self.logger.info("Adding {} IRQs...".format(colorer("reserved", color="cyan"))) self.logger.info("Adding {} IRQs...".format(colorer("reserved", color="cyan")))
for name, n in reserved_irqs.items(): for name, n in reserved_irqs.items():
self.add(name, n) self.add(name, n)
@ -657,11 +660,7 @@ class SoCIRQHandler(SoCLocHandler):
# SoCController ------------------------------------------------------------------------------------ # SoCController ------------------------------------------------------------------------------------
class SoCController(Module, AutoCSR): class SoCController(Module, AutoCSR):
def __init__(self, def __init__(self, with_reset=True, with_scratch=True, with_errors=True):
with_reset = True,
with_scratch = True,
with_errors = True):
if with_reset: if with_reset:
self._reset = CSRStorage(1, description="""Any write to this register will reset the SoC.""") self._reset = CSRStorage(1, description="""Any write to this register will reset the SoC.""")
if with_scratch: if with_scratch:
@ -848,13 +847,15 @@ class SoC(Module):
self.add_config("CSR_ALIGNMENT", self.csr.alignment) self.add_config("CSR_ALIGNMENT", self.csr.alignment)
def add_cpu(self, name="vexriscv", variant="standard", cls=None, reset_address=None): def add_cpu(self, name="vexriscv", variant="standard", cls=None, reset_address=None):
# Check that CPU is supported.
if name not in cpu.CPUS.keys(): if name not in cpu.CPUS.keys():
self.logger.error("{} CPU {}, supporteds: {}.".format( self.logger.error("{} CPU {}, supporteds: {}.".format(
colorer(name), colorer(name),
colorer("not supported", color="red"), colorer("not supported", color="red"),
colorer(", ".join(cpu.CPUS.keys())))) colorer(", ".join(cpu.CPUS.keys()))))
raise raise
# Add CPU
# Add CPU.
if name == "external" and cls is None: if name == "external" and cls is None:
self.logger.error("{} CPU requires {} to be specified.".format( self.logger.error("{} CPU requires {} to be specified.".format(
colorer(name), colorer(name),
@ -868,11 +869,13 @@ class SoC(Module):
colorer(", ".join(cpu_cls.variants)))) colorer(", ".join(cpu_cls.variants))))
raise raise
self.submodules.cpu = cpu_cls(self.platform, variant) self.submodules.cpu = cpu_cls(self.platform, variant)
# Update SoC with CPU constraints
# Update SoC with CPU constraints.
for n, (origin, size) in enumerate(self.cpu.io_regions.items()): for n, (origin, size) in enumerate(self.cpu.io_regions.items()):
self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False)) self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
self.mem_map.update(self.cpu.mem_map) # FIXME self.mem_map.update(self.cpu.mem_map) # FIXME
# Add Bus Masters/CSR/IRQs
# Add Bus Masters/CSR/IRQs.
if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)): if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
if reset_address is None: if reset_address is None:
reset_address = self.mem_map["rom"] reset_address = self.mem_map["rom"]
@ -886,7 +889,7 @@ class SoC(Module):
self.irq.add(name, loc) self.irq.add(name, loc)
self.add_config("CPU_HAS_INTERRUPT") self.add_config("CPU_HAS_INTERRUPT")
# Create optional DMA Bus (for Cache Coherence) # Create optional DMA Bus (for Cache Coherence).
if hasattr(self.cpu, "dma_bus"): if hasattr(self.cpu, "dma_bus"):
self.submodules.dma_bus = SoCBusHandler( self.submodules.dma_bus = SoCBusHandler(
name = "SoCDMABusHandler", name = "SoCDMABusHandler",
@ -898,17 +901,17 @@ class SoC(Module):
self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only
self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus) self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus)
# Connect SoCController's reset to CPU reset # Connect SoCController's reset to CPU reset.
if hasattr(self, "ctrl"): if hasattr(self, "ctrl"):
if hasattr(self.ctrl, "reset"): if hasattr(self.ctrl, "reset"):
self.comb += self.cpu.reset.eq(self.ctrl.reset) self.comb += self.cpu.reset.eq(self.ctrl.reset)
self.add_config("CPU_RESET_ADDR", reset_address) self.add_config("CPU_RESET_ADDR", reset_address)
# Add CPU's SoC components (if any) # Add CPU's SoC components (if any).
if hasattr(self.cpu, "add_soc_components"): if hasattr(self.cpu, "add_soc_components"):
self.cpu.add_soc_components(soc=self, soc_region_cls=SoCRegion) # FIXME: avoid passing SoCRegion. self.cpu.add_soc_components(soc=self, soc_region_cls=SoCRegion) # FIXME: avoid passing SoCRegion.
# Add constants # Add constants.
self.add_config("CPU_TYPE", str(name)) self.add_config("CPU_TYPE", str(name))
self.add_config("CPU_VARIANT", str(variant.split('+')[0])) self.add_config("CPU_VARIANT", str(variant.split('+')[0]))
self.add_constant("CONFIG_CPU_HUMAN_NAME", getattr(self.cpu, "human_name", "Unknown")) self.add_constant("CONFIG_CPU_HUMAN_NAME", getattr(self.cpu, "human_name", "Unknown"))
@ -1018,24 +1021,24 @@ class SoC(Module):
masters = list(self.csr.masters.values()), masters = list(self.csr.masters.values()),
slaves = self.csr_bankarray.get_buses()) slaves = self.csr_bankarray.get_buses())
# Add CSRs regions # Add CSRs regions.
for name, csrs, mapaddr, rmap in self.csr_bankarray.banks: for name, csrs, mapaddr, rmap in self.csr_bankarray.banks:
self.csr.add_region(name, SoCCSRRegion( self.csr.add_region(name, SoCCSRRegion(
origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr), origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr),
busword = self.csr.data_width, busword = self.csr.data_width,
obj = csrs)) obj = csrs))
# Add Memory regions # Add Memory regions.
for name, memory, mapaddr, mmap in self.csr_bankarray.srams: for name, memory, mapaddr, mmap in self.csr_bankarray.srams:
self.csr.add_region(name + "_" + memory.name_override, SoCCSRRegion( self.csr.add_region(name + "_" + memory.name_override, SoCCSRRegion(
origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr), origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr),
busword = self.csr.data_width, busword = self.csr.data_width,
obj = memory)) obj = memory))
# Sort CSR regions by origin # Sort CSR regions by origin.
self.csr.regions = {k: v for k, v in sorted(self.csr.regions.items(), key=lambda item: item[1].origin)} self.csr.regions = {k: v for k, v in sorted(self.csr.regions.items(), key=lambda item: item[1].origin)}
# Add CSRs / Config items to constants # Add CSRs / Config items to constants.
for name, constant in self.csr_bankarray.constants: for name, constant in self.csr_bankarray.constants:
self.add_constant(name + "_" + constant.name, constant.value.value) self.add_constant(name + "_" + constant.name, constant.value.value)
@ -1100,37 +1103,37 @@ class LiteXSoC(SoC):
def add_uart(self, name, baudrate=115200, fifo_depth=16): def add_uart(self, name, baudrate=115200, fifo_depth=16):
from litex.soc.cores import uart from litex.soc.cores import uart
# Stub / Stream # Stub / Stream.
if name in ["stub", "stream"]: if name in ["stub", "stream"]:
self.submodules.uart = uart.UART(tx_fifo_depth=0, rx_fifo_depth=0) self.submodules.uart = uart.UART(tx_fifo_depth=0, rx_fifo_depth=0)
if name == "stub": if name == "stub":
self.comb += self.uart.sink.ready.eq(1) self.comb += self.uart.sink.ready.eq(1)
# UARTBone / Bridge # UARTBone / Bridge.
elif name in ["uartbone", "bridge"]: elif name in ["uartbone", "bridge"]:
self.add_uartbone(baudrate=baudrate) self.add_uartbone(baudrate=baudrate)
# Crossover # Crossover.
elif name in ["crossover"]: elif name in ["crossover"]:
self.submodules.uart = uart.UARTCrossover( self.submodules.uart = uart.UARTCrossover(
tx_fifo_depth = fifo_depth, tx_fifo_depth = fifo_depth,
rx_fifo_depth = fifo_depth) rx_fifo_depth = fifo_depth)
# Crossover + Bridge # Crossover + Bridge.
elif name in ["crossover+bridge"]: elif name in ["crossover+bridge"]:
self.add_uartbone(baudrate=baudrate) self.add_uartbone(baudrate=baudrate)
self.submodules.uart = uart.UARTCrossover( self.submodules.uart = uart.UARTCrossover(
tx_fifo_depth = fifo_depth, tx_fifo_depth = fifo_depth,
rx_fifo_depth = fifo_depth) rx_fifo_depth = fifo_depth)
# Model/Sim # Model/Sim.
elif name in ["model", "sim"]: elif name in ["model", "sim"]:
self.submodules.uart_phy = uart.RS232PHYModel(self.platform.request("serial")) self.submodules.uart_phy = uart.RS232PHYModel(self.platform.request("serial"))
self.submodules.uart = uart.UART(self.uart_phy, self.submodules.uart = uart.UART(self.uart_phy,
tx_fifo_depth = fifo_depth, tx_fifo_depth = fifo_depth,
rx_fifo_depth = fifo_depth) rx_fifo_depth = fifo_depth)
# JTAG Atlantic # JTAG Atlantic.
elif name in ["jtag_atlantic"]: elif name in ["jtag_atlantic"]:
from litex.soc.cores.jtag import JTAGAtlantic from litex.soc.cores.jtag import JTAGAtlantic
self.submodules.uart_phy = JTAGAtlantic() self.submodules.uart_phy = JTAGAtlantic()
@ -1138,7 +1141,7 @@ class LiteXSoC(SoC):
tx_fifo_depth = fifo_depth, tx_fifo_depth = fifo_depth,
rx_fifo_depth = fifo_depth) rx_fifo_depth = fifo_depth)
# JTAG UART # JTAG UART.
elif name in ["jtag_uart"]: elif name in ["jtag_uart"]:
from litex.soc.cores.jtag import JTAGPHY from litex.soc.cores.jtag import JTAGPHY
self.clock_domains.cd_sys_jtag = ClockDomain() # Run JTAG-UART in sys_jtag clock domain similar to self.clock_domains.cd_sys_jtag = ClockDomain() # Run JTAG-UART in sys_jtag clock domain similar to
@ -1148,7 +1151,7 @@ class LiteXSoC(SoC):
tx_fifo_depth = fifo_depth, tx_fifo_depth = fifo_depth,
rx_fifo_depth = fifo_depth) rx_fifo_depth = fifo_depth)
# USB ACM (with ValentyUSB core) # USB ACM (with ValentyUSB core).
elif name in ["usb_acm"]: elif name in ["usb_acm"]:
import valentyusb.usbcore.io as usbio import valentyusb.usbcore.io as usbio
import valentyusb.usbcore.cpu.cdc_eptri as cdc_eptri import valentyusb.usbcore.cpu.cdc_eptri as cdc_eptri
@ -1158,7 +1161,7 @@ class LiteXSoC(SoC):
self.comb += self.cd_sys_usb.clk.eq(ClockSignal("sys")) # sys clock domain but with rst disconnected. self.comb += self.cd_sys_usb.clk.eq(ClockSignal("sys")) # sys clock domain but with rst disconnected.
self.submodules.uart = ClockDomainsRenamer("sys_usb")(cdc_eptri.CDCUsb(usb_iobuf)) self.submodules.uart = ClockDomainsRenamer("sys_usb")(cdc_eptri.CDCUsb(usb_iobuf))
# Classic UART # Classical UART.
else: else:
self.submodules.uart_phy = uart.UARTPHY( self.submodules.uart_phy = uart.UARTPHY(
pads = self.platform.request(name), pads = self.platform.request(name),
@ -1201,14 +1204,14 @@ class LiteXSoC(SoC):
l2_cache_full_memory_we = True, l2_cache_full_memory_we = True,
**kwargs): **kwargs):
# Imports # Imports.
from litedram.common import LiteDRAMNativePort from litedram.common import LiteDRAMNativePort
from litedram.core import LiteDRAMCore from litedram.core import LiteDRAMCore
from litedram.frontend.wishbone import LiteDRAMWishbone2Native from litedram.frontend.wishbone import LiteDRAMWishbone2Native
from litedram.frontend.axi import LiteDRAMAXI2Native from litedram.frontend.axi import LiteDRAMAXI2Native
from litedram.frontend.bist import LiteDRAMBISTGenerator, LiteDRAMBISTChecker from litedram.frontend.bist import LiteDRAMBISTGenerator, LiteDRAMBISTChecker
# LiteDRAM core # LiteDRAM core.
self.submodules.sdram = LiteDRAMCore( self.submodules.sdram = LiteDRAMCore(
phy = phy, phy = phy,
geom_settings = module.geom_settings, geom_settings = module.geom_settings,
@ -1217,9 +1220,9 @@ class LiteXSoC(SoC):
**kwargs) **kwargs)
self.csr.add("sdram", use_loc_if_exists=True) self.csr.add("sdram", use_loc_if_exists=True)
# Save SPD data to be able to verify it at runtime # Save SPD data to be able to verify it at runtime.
if hasattr(module, "_spd_data"): if hasattr(module, "_spd_data"):
# pack the data into words of bus width # Pack the data into words of bus width.
bytes_per_word = self.bus.data_width // 8 bytes_per_word = self.bus.data_width // 8
mem = [0] * ceil(len(module._spd_data) / bytes_per_word) mem = [0] * ceil(len(module._spd_data) / bytes_per_word)
for i in range(len(mem)): for i in range(len(mem)):
@ -1237,7 +1240,7 @@ class LiteXSoC(SoC):
contents = mem, contents = mem,
) )
# LiteDRAM BIST # LiteDRAM BIST.
if with_bist: if with_bist:
self.submodules.sdram_generator = LiteDRAMBISTGenerator(self.sdram.crossbar.get_port()) self.submodules.sdram_generator = LiteDRAMBISTGenerator(self.sdram.crossbar.get_port())
self.csr.add("sdram_generator") self.csr.add("sdram_generator")
@ -1246,14 +1249,14 @@ class LiteXSoC(SoC):
if not with_soc_interconnect: return if not with_soc_interconnect: return
# Compute/Check SDRAM size # Compute/Check SDRAM size.
sdram_size = 2**(module.geom_settings.bankbits + sdram_size = 2**(module.geom_settings.bankbits +
module.geom_settings.rowbits + module.geom_settings.rowbits +
module.geom_settings.colbits)*phy.settings.databits//8 module.geom_settings.colbits)*phy.settings.databits//8
if size is not None: if size is not None:
sdram_size = min(sdram_size, size) sdram_size = min(sdram_size, size)
# Add SDRAM region # Add SDRAM region.
self.bus.add_region("main_ram", SoCRegion(origin=origin, size=sdram_size)) self.bus.add_region("main_ram", SoCRegion(origin=origin, size=sdram_size))
# Add CPU's direct memory buses (if not already declared) ---------------------------------- # Add CPU's direct memory buses (if not already declared) ----------------------------------
@ -1285,11 +1288,11 @@ class LiteXSoC(SoC):
self.logger.info("Converting MEM data width: {} to {} via Wishbone".format( self.logger.info("Converting MEM data width: {} to {} via Wishbone".format(
port.data_width, port.data_width,
self.cpu.mem_axi.data_width)) self.cpu.mem_axi.data_width))
# FIXME: replace WB data-width converter with native AXI converter!!! # FIXME: Replace WB data-width converter with native AXI converter.
mem_wb = wishbone.Interface( mem_wb = wishbone.Interface(
data_width = self.cpu.mem_axi.data_width, data_width = self.cpu.mem_axi.data_width,
adr_width = 32-log2_int(self.cpu.mem_axi.data_width//8)) adr_width = 32-log2_int(self.cpu.mem_axi.data_width//8))
# NOTE: AXI2Wishbone FSMs must be reset with the CPU! # FIXME: AXI2Wishbone FSMs must be reset with the CPU.
mem_a2w = ResetInserter()(axi.AXI2Wishbone( mem_a2w = ResetInserter()(axi.AXI2Wishbone(
axi = self.cpu.mem_axi, axi = self.cpu.mem_axi,
wishbone = mem_wb, wishbone = mem_wb,
@ -1349,7 +1352,7 @@ class LiteXSoC(SoC):
self.submodules += wishbone.Converter(wb_sdram, litedram_wb) self.submodules += wishbone.Converter(wb_sdram, litedram_wb)
self.add_config("L2_SIZE", l2_cache_size) self.add_config("L2_SIZE", l2_cache_size)
# Wishbone Slave <--> LiteDRAM bridge # Wishbone Slave <--> LiteDRAM bridge.
self.submodules.wishbone_bridge = LiteDRAMWishbone2Native( self.submodules.wishbone_bridge = LiteDRAMWishbone2Native(
wishbone = litedram_wb, wishbone = litedram_wb,
port = port, port = port,
@ -1361,23 +1364,26 @@ class LiteXSoC(SoC):
from liteeth.mac import LiteEthMAC from liteeth.mac import LiteEthMAC
from liteeth.phy.model import LiteEthPHYModel from liteeth.phy.model import LiteEthPHYModel
# MAC # MAC.
ethmac = LiteEthMAC( ethmac = LiteEthMAC(
phy = phy, phy = phy,
dw = 32, dw = 32,
interface = "wishbone", interface = "wishbone",
endianness = self.cpu.endianness, endianness = self.cpu.endianness,
with_preamble_crc = not software_debug,
nrxslots = nrxslots, nrxslots = nrxslots,
ntxslots = ntxslots) ntxslots = ntxslots,
with_preamble_crc = not software_debug)
# Use PHY's eth_tx/eth_rx clock domains.
ethmac = ClockDomainsRenamer({ ethmac = ClockDomainsRenamer({
"eth_tx": phy_cd + "_tx", "eth_tx": phy_cd + "_tx",
"eth_rx": phy_cd + "_rx"})(ethmac) "eth_rx": phy_cd + "_rx"})(ethmac)
setattr(self.submodules, name, ethmac) setattr(self.submodules, name, ethmac)
ethmac_region_size = (ethmac.rx_slots.read()+ethmac.tx_slots.read())*ethmac.slot_size.read() # Compute Regions size and add it to the SoC.
ethmac_region_size = (ethmac.rx_slots.read() + ethmac.tx_slots.read())*ethmac.slot_size.read()
ethmac_region = SoCRegion(origin=self.mem_map.get(name, None), size=ethmac_region_size, cached=False) ethmac_region = SoCRegion(origin=self.mem_map.get(name, None), size=ethmac_region_size, cached=False)
self.bus.add_slave(name=name, slave=ethmac.bus, region=ethmac_region) self.bus.add_slave(name=name, slave=ethmac.bus, region=ethmac_region)
self.csr.add(name, use_loc_if_exists=True) self.csr.add(name, use_loc_if_exists=True)
# Add IRQs (if enabled).
if self.irq.enabled: if self.irq.enabled:
self.irq.add(name, use_loc_if_exists=True) self.irq.add(name, use_loc_if_exists=True)
@ -1389,6 +1395,7 @@ class LiteXSoC(SoC):
self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq) self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq)
self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk)
# Dynamic IP (if enabled).
if dynamic_ip: if dynamic_ip:
self.add_constant("ETH_DYNAMIC_IP") self.add_constant("ETH_DYNAMIC_IP")
@ -1414,13 +1421,14 @@ class LiteXSoC(SoC):
mac_address = mac_address, mac_address = mac_address,
ip_address = ip_address, ip_address = ip_address,
clk_freq = self.clk_freq) clk_freq = self.clk_freq)
# Use PHY's eth_tx/eth_rx clock domains.
ethcore = ClockDomainsRenamer({ ethcore = ClockDomainsRenamer({
"eth_tx": phy_cd + "_tx", "eth_tx": phy_cd + "_tx",
"eth_rx": phy_cd + "_rx", "eth_rx": phy_cd + "_rx",
"sys": phy_cd + "_rx"})(ethcore) "sys": phy_cd + "_rx"})(ethcore)
self.submodules.ethcore = ethcore self.submodules.ethcore = ethcore
# Clock domain renaming # Create Etherbone clock domain and run it from sys clock domain.
self.clock_domains.cd_etherbone = ClockDomain("etherbone") self.clock_domains.cd_etherbone = ClockDomain("etherbone")
self.comb += self.cd_etherbone.clk.eq(ClockSignal("sys")) self.comb += self.cd_etherbone.clk.eq(ClockSignal("sys"))
self.comb += self.cd_etherbone.rst.eq(ResetSignal("sys")) self.comb += self.cd_etherbone.rst.eq(ResetSignal("sys"))
@ -1483,14 +1491,16 @@ class LiteXSoC(SoC):
# Add SDCard ----------------------------------------------------------------------------------- # Add SDCard -----------------------------------------------------------------------------------
def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, software_debug=False): def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, software_debug=False):
assert mode in ["read", "write", "read+write"] # Imports.
# Imports
from litesdcard.emulator import SDEmulator from litesdcard.emulator import SDEmulator
from litesdcard.phy import SDPHY from litesdcard.phy import SDPHY
from litesdcard.core import SDCore from litesdcard.core import SDCore
from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA
# Emulator / Pads # Checks.
assert mode in ["read", "write", "read+write"]
# Emulator / Pads.
if use_emulator: if use_emulator:
sdemulator = SDEmulator(self.platform) sdemulator = SDEmulator(self.platform)
self.submodules += sdemulator self.submodules += sdemulator
@ -1498,13 +1508,13 @@ class LiteXSoC(SoC):
else: else:
sdcard_pads = self.platform.request(name) sdcard_pads = self.platform.request(name)
# Core # Core.
self.submodules.sdphy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq, cmd_timeout=10e-1, data_timeout=10e-1) self.submodules.sdphy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq, cmd_timeout=10e-1, data_timeout=10e-1)
self.submodules.sdcore = SDCore(self.sdphy) self.submodules.sdcore = SDCore(self.sdphy)
self.csr.add("sdphy", use_loc_if_exists=True) self.csr.add("sdphy", use_loc_if_exists=True)
self.csr.add("sdcore", use_loc_if_exists=True) self.csr.add("sdcore", use_loc_if_exists=True)
# Block2Mem DMA # Block2Mem DMA.
if "read" in mode: if "read" in mode:
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) 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.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
@ -1513,7 +1523,7 @@ class LiteXSoC(SoC):
dma_bus.add_master("sdblock2mem", master=bus) dma_bus.add_master("sdblock2mem", master=bus)
self.csr.add("sdblock2mem", use_loc_if_exists=True) self.csr.add("sdblock2mem", use_loc_if_exists=True)
# Mem2Block DMA # Mem2Block DMA.
if "write" in mode: if "write" in mode:
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) 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.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
@ -1522,7 +1532,7 @@ class LiteXSoC(SoC):
dma_bus.add_master("sdmem2block", master=bus) dma_bus.add_master("sdmem2block", master=bus)
self.csr.add("sdmem2block", use_loc_if_exists=True) self.csr.add("sdmem2block", use_loc_if_exists=True)
# Interrupts # Interrupts.
self.submodules.sdirq = EventManager() self.submodules.sdirq = EventManager()
self.sdirq.card_detect = EventSourcePulse(description="SDCard has been ejected/inserted.") self.sdirq.card_detect = EventSourcePulse(description="SDCard has been ejected/inserted.")
self.sdirq.block2mem_dma = EventSourcePulse(description="Block2Mem DMA terminated.") self.sdirq.block2mem_dma = EventSourcePulse(description="Block2Mem DMA terminated.")
@ -1535,18 +1545,18 @@ class LiteXSoC(SoC):
self.sdirq.mem2block_dma.trigger.eq(self.sdmem2block.irq), self.sdirq.mem2block_dma.trigger.eq(self.sdmem2block.irq),
] ]
# Software Debug # Debug.
if software_debug: if software_debug:
self.add_constant("SDCARD_DEBUG") self.add_constant("SDCARD_DEBUG")
# Add SATA ------------------------------------------------------------------------------------- # Add SATA -------------------------------------------------------------------------------------
def add_sata(self, name="sata", phy=None, mode="read+write"): def add_sata(self, name="sata", phy=None, mode="read+write"):
# Imports # Imports.
from litesata.core import LiteSATACore from litesata.core import LiteSATACore
from litesata.frontend.arbitration import LiteSATACrossbar from litesata.frontend.arbitration import LiteSATACrossbar
from litesata.frontend.dma import LiteSATASector2MemDMA, LiteSATAMem2SectorDMA from litesata.frontend.dma import LiteSATASector2MemDMA, LiteSATAMem2SectorDMA
# Checks # Checks.
assert mode in ["read", "write", "read+write"] assert mode in ["read", "write", "read+write"]
sata_clk_freqs = { sata_clk_freqs = {
"gen1": 75e6, "gen1": 75e6,
@ -1556,13 +1566,13 @@ class LiteXSoC(SoC):
sata_clk_freq = sata_clk_freqs[phy.gen] sata_clk_freq = sata_clk_freqs[phy.gen]
assert self.clk_freq >= sata_clk_freq/2 # FIXME: /2 for 16-bit data-width, add support for 32-bit. assert self.clk_freq >= sata_clk_freq/2 # FIXME: /2 for 16-bit data-width, add support for 32-bit.
# Core # Core.
self.submodules.sata_core = LiteSATACore(phy) self.submodules.sata_core = LiteSATACore(phy)
# Crossbar # Crossbar.
self.submodules.sata_crossbar = LiteSATACrossbar(self.sata_core) self.submodules.sata_crossbar = LiteSATACrossbar(self.sata_core)
# Sector2Mem DMA # Sector2Mem DMA.
if "read" in mode: if "read" in mode:
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sata_sector2mem = LiteSATASector2MemDMA( self.submodules.sata_sector2mem = LiteSATASector2MemDMA(
@ -1573,7 +1583,7 @@ class LiteXSoC(SoC):
dma_bus.add_master("sata_sector2mem", master=bus) dma_bus.add_master("sata_sector2mem", master=bus)
self.csr.add("sata_sector2mem", use_loc_if_exists=True) self.csr.add("sata_sector2mem", use_loc_if_exists=True)
# Mem2Sector DMA # Mem2Sector DMA.
if "write" in mode: if "write" in mode:
bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width) bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
self.submodules.sata_mem2sector = LiteSATAMem2SectorDMA( self.submodules.sata_mem2sector = LiteSATAMem2SectorDMA(
@ -1584,7 +1594,7 @@ class LiteXSoC(SoC):
dma_bus.add_master("sata_mem2sector", master=bus) dma_bus.add_master("sata_mem2sector", master=bus)
self.csr.add("sata_mem2sector", use_loc_if_exists=True) self.csr.add("sata_mem2sector", use_loc_if_exists=True)
# Timing constraints # Timing constraints.
self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_tx.clk, 1e9/sata_clk_freq) self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_tx.clk, 1e9/sata_clk_freq)
self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_rx.clk, 1e9/sata_clk_freq) self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_rx.clk, 1e9/sata_clk_freq)
self.platform.add_false_path_constraints( self.platform.add_false_path_constraints(
@ -1594,24 +1604,25 @@ class LiteXSoC(SoC):
# Add PCIe ------------------------------------------------------------------------------------- # Add PCIe -------------------------------------------------------------------------------------
def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, with_msi=True): def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, with_msi=True):
assert self.csr.data_width == 32
assert not hasattr(self, f"{name}_endpoint")
# Imports # Imports
from litepcie.core import LitePCIeEndpoint, LitePCIeMSI from litepcie.core import LitePCIeEndpoint, LitePCIeMSI
from litepcie.frontend.dma import LitePCIeDMA from litepcie.frontend.dma import LitePCIeDMA
from litepcie.frontend.wishbone import LitePCIeWishboneMaster from litepcie.frontend.wishbone import LitePCIeWishboneMaster
# Endpoint # Checks.
assert self.csr.data_width == 32
assert not hasattr(self, f"{name}_endpoint")
# Endpoint.
endpoint = LitePCIeEndpoint(phy, max_pending_requests=max_pending_requests) endpoint = LitePCIeEndpoint(phy, max_pending_requests=max_pending_requests)
setattr(self.submodules, f"{name}_endpoint", endpoint) setattr(self.submodules, f"{name}_endpoint", endpoint)
# MMAP # MMAP.
mmap = LitePCIeWishboneMaster(self.pcie_endpoint, base_address=self.mem_map["csr"]) mmap = LitePCIeWishboneMaster(self.pcie_endpoint, base_address=self.mem_map["csr"])
self.add_wb_master(mmap.wishbone) self.add_wb_master(mmap.wishbone)
setattr(self.submodules, f"{name}_mmap", mmap) setattr(self.submodules, f"{name}_mmap", mmap)
# MSI # MSI.
if with_msi: if with_msi:
msi = LitePCIeMSI() msi = LitePCIeMSI()
setattr(self.submodules, f"{name}_msi", msi) setattr(self.submodules, f"{name}_msi", msi)
@ -1619,7 +1630,7 @@ class LiteXSoC(SoC):
self.comb += msi.source.connect(phy.msi) self.comb += msi.source.connect(phy.msi)
self.msis = {} self.msis = {}
# DMAs # DMAs.
for i in range(ndmas): for i in range(ndmas):
assert with_msi assert with_msi
dma = LitePCIeDMA(phy, endpoint, dma = LitePCIeDMA(phy, endpoint,
@ -1631,13 +1642,13 @@ class LiteXSoC(SoC):
self.msis[f"{name.upper()}_DMA{i}_READER"] = dma.reader.irq self.msis[f"{name.upper()}_DMA{i}_READER"] = dma.reader.irq
self.add_constant("DMA_CHANNELS", ndmas) self.add_constant("DMA_CHANNELS", ndmas)
# Map/Connect IRQs # Map/Connect IRQs.
if with_msi: if with_msi:
for i, (k, v) in enumerate(sorted(self.msis.items())): for i, (k, v) in enumerate(sorted(self.msis.items())):
self.comb += msi.irqs[i].eq(v) self.comb += msi.irqs[i].eq(v)
self.add_constant(k + "_INTERRUPT", i) self.add_constant(k + "_INTERRUPT", i)
# Timing constraints # Timing constraints.
self.platform.add_false_path_constraints(self.crg.cd_sys.clk, phy.cd_pcie.clk) self.platform.add_false_path_constraints(self.crg.cd_sys.clk, phy.cd_pcie.clk)
# Add Video ColorBars Pattern ------------------------------------------------------------------ # Add Video ColorBars Pattern ------------------------------------------------------------------