soc_core: add new alloc_mem/add_mem_region to allow automatic allocation of memory regions

With add_memory_region, user needs to provide the memory origin, which should not be needed since
could be retrieved from mem_map and prevent automatic allocation which is already possible for csr
and interrupts.

New add_mem_region method now allows both: defining the memory origin in mem_map (which will then
be used) or let the SoC builder automatically find and allocate a memory region.
This commit is contained in:
Florent Kermarrec 2020-01-20 12:05:08 +01:00
parent eae0e00496
commit 53bc18cc3f
1 changed files with 58 additions and 13 deletions

View File

@ -403,23 +403,68 @@ class SoCCore(Module):
i += 1
return None
def alloc_mem_region(self, name, length, type):
# Use type to limit search regions
search_regions = []
if "io" in type:
for _origin, _length in self.soc_io_regions.items():
search_regions.append(SoCMemRegion(origin=_origin, length=_length, type=type))
else:
search_regions.append(SoCMemRegion(origin=0x00000000, length=0x80000000, type=type))
# Iterate over search_regions and origin to find a candidate region
for search_region in search_regions:
origin = search_region.origin
while (origin + length) < (search_region.origin + search_region.length):
# Create a candidate mem region.
candidate_region = SoCMemRegion(origin=origin, length=length, type=type)
candidate_overlap = False
# Check candidate does not overlap with allocated mem regions.
for _, allocated_region in self.mem_regions.items():
if self.check_regions_overlap({"0": allocated_region, "1": candidate_region}) is not None:
origin = allocated_region.origin + allocated_region.length
candidate_overlap = True
break
if not candidate_overlap:
# If no overlap, the candidate is selected.
#print("{} region allocated at: {:08x}".format(name, candidate_region.origin))
return candidate_region
msg = "Not enough addressable memory space to allocate mem region {} of length 0x{:0x}".format(
name, length)
raise ValueError(msg)
def add_mem_region(self, name, length, type="cached"):
# Check name conflicts.
if name in self.mem_regions.keys():
raise ValueError("Memory region conflict, {} name already used".format(name))
# Round length to next power of 2.
length = 2**log2_int(length, False)
# Get mem origin; if not defined in mem_map, allocate a new mem region, else use mem_map
# mapping and check for type/overlap conflicts.
origin = self.mem_map.get(name, None)
if origin is None:
self.mem_regions[name] = self.alloc_mem_region(name, length, type)
else:
# Check type
if "io" in type:
self.check_io_region(name,origin, length)
# Add region
self.mem_regions[name] = SoCMemRegion(origin, length, type)
# Check overlap
overlap = self.check_regions_overlap(self.mem_regions)
if overlap is not None:
o0, o1 = overlap[0], overlap[1]
raise ValueError("Memory region conflict between {} ({}) and {} ({})".format(
o0, self.mem_regions[o0],
o1, self.mem_regions[o1],
))
# FIXME: add deprecated warning?
def add_memory_region(self, name, origin, length, type="cached", io_region=False):
if io_region: # 2019-10-30: io_region retro-compatibility
deprecated_warning(": io_region replaced by type=\"io\".")
type = "io"
length = 2**log2_int(length, False)
if "io" in type:
self.check_io_region(name, origin, length)
if name in self.mem_regions.keys():
raise ValueError("Memory region conflict, {} name already used".format(name))
self.mem_regions[name] = SoCMemRegion(origin, length, type)
overlap = self.check_regions_overlap(self.mem_regions)
if overlap is not None:
o0, o1 = overlap[0], overlap[1]
raise ValueError("Memory region conflict between {} ({}) and {} ({})".format(
o0, self.mem_regions[o0],
o1, self.mem_regions[o1],
))
assert name in self.mem_map.keys()
self.add_mem_region(name, length, type)
def register_mem(self, name, address, interface, size=0x10000000):
self.add_wb_slave(address, interface, size)