A range map is a mapping from non-overlapping ranges to arbitrary values.
"""
+
def __init__(self):
- self._keys = []
+ self._keys = []
self._values = dict()
self._starts = []
- self._stops = []
+ self._stops = []
def insert(self, key, value):
assert isinstance(key, range)
assert not self.overlaps(key)
start_idx = bisect.bisect_right(self._starts, key.start)
- stop_idx = bisect.bisect_left(self._stops, key.stop)
+ stop_idx = bisect.bisect_left(self._stops, key.stop)
assert start_idx == stop_idx
self._starts.insert(start_idx, key.start)
def overlaps(self, key):
start_idx = bisect.bisect_right(self._stops, key.start)
- stop_idx = bisect.bisect_left(self._starts, key.stop)
+ stop_idx = bisect.bisect_left(self._starts, key.stop)
return [self._values[key] for key in self._keys[start_idx:stop_idx]]
def items(self):
at an address that is a multiple of ``2 ** alignment``, and its
size will be rounded up to be a multiple of ``2 ** alignment``.
"""
+
def __init__(self, *, addr_width, data_width, alignment=0):
if not isinstance(addr_width, int) or addr_width <= 0:
- raise ValueError("Address width must be a positive integer, not {!r}"
- .format(addr_width))
+ raise ValueError("Address width must be a positive integer, "
+ "not {!r}" .format(addr_width))
if not isinstance(data_width, int) or data_width <= 0:
- raise ValueError("Data width must be a positive integer, not {!r}"
- .format(data_width))
+ raise ValueError("Data width must be a positive integer, "
+ "not {!r}" .format(data_width))
if not isinstance(alignment, int) or alignment < 0:
- raise ValueError("Alignment must be a non-negative integer, not {!r}"
- .format(alignment))
+ raise ValueError("Alignment must be a non-negative integer, "
+ "not {!r}" .format(alignment))
self.addr_width = addr_width
self.data_width = data_width
- self.alignment = alignment
+ self.alignment = alignment
- self._ranges = _RangeMap()
+ self._ranges = _RangeMap()
self._resources = dict()
- self._windows = dict()
+ self._windows = dict()
self._next_addr = 0
Implicit next address.
"""
if not isinstance(alignment, int) or alignment < 0:
- raise ValueError("Alignment must be a non-negative integer, not {!r}"
- .format(alignment))
- self._next_addr = self._align_up(self._next_addr, max(alignment, self.alignment))
+ raise ValueError("Alignment must be a non-negative integer, "
+ "not {!r}" .format(alignment))
+ self._next_addr = self._align_up(
+ self._next_addr, max(
+ alignment, self.alignment))
return self._next_addr
def _compute_addr_range(self, addr, size, step=1, *, alignment):
if addr is not None:
if not isinstance(addr, int) or addr < 0:
- raise ValueError("Address must be a non-negative integer, not {!r}"
- .format(addr))
+ raise ValueError("Address must be a non-negative integer, "
+ "not {!r}" .format(addr))
if addr % (1 << self.alignment) != 0:
- raise ValueError("Explicitly specified address {:#x} must be a multiple of "
- "{:#x} bytes"
- .format(addr, 1 << alignment))
+ raise ValueError("Explicitly specified address {:#x} "
+ "must be a multiple of "
+ "{:#x} bytes".format(addr, 1 << alignment))
else:
addr = self._align_up(self._next_addr, alignment)
.format(size))
size = self._align_up(size, alignment)
- if addr > (1 << self.addr_width) or addr + size > (1 << self.addr_width):
+ if addr > (1 << self.addr_width) or addr + \
+ size > (1 << self.addr_width):
raise ValueError("Address range {:#x}..{:#x} out of bounds for memory map spanning "
"range {:#x}..{:#x} ({} address bits)"
- .format(addr, addr + size, 0, 1 << self.addr_width, self.addr_width))
+ .format(addr, addr + size, 0,
+ 1 << self.addr_width, self.addr_width))
addr_range = range(addr, addr + size, step)
overlaps = self._ranges.overlaps(addr_range)
if overlap in self._resources:
resource_range = self._resources[overlap]
overlap_descrs.append("resource {!r} at {:#x}..{:#x}"
- .format(overlap, resource_range.start, resource_range.stop))
+ .format(overlap,
+ resource_range.start,
+ resource_range.stop))
if overlap in self._windows:
window_range = self._windows[overlap]
overlap_descrs.append("window {!r} at {:#x}..{:#x}"
- .format(overlap, window_range.start, window_range.stop))
+ .format(overlap,
+ window_range.start,
+ window_range.stop))
raise ValueError("Address range {:#x}..{:#x} overlaps with {}"
- .format(addr, addr + size, ", ".join(overlap_descrs)))
+ .format(addr,
+ addr + size,
+ ", ".join(overlap_descrs)))
return addr_range
"""
if resource in self._resources:
addr_range = self._resources[resource]
- raise ValueError("Resource {!r} is already added at address range {:#x}..{:#x}"
- .format(resource, addr_range.start, addr_range.stop))
+ raise ValueError("Resource {!r} is already added at "
+ "address range {:#x}..{:#x}"
+ .format(resource, addr_range.start,
+ addr_range.stop))
if alignment is not None:
if not isinstance(alignment, int) or alignment < 0:
- raise ValueError("Alignment must be a non-negative integer, not {!r}"
- .format(alignment))
+ raise ValueError("Alignment must be a non-negative integer, "
+ "not {!r}" .format(alignment))
alignment = max(alignment, self.alignment)
else:
alignment = self.alignment
.format(window))
if window in self._windows:
addr_range = self._windows[window]
- raise ValueError("Window {!r} is already added at address range {:#x}..{:#x}"
+ raise ValueError("Window {!r} is already added at "
+ "address range {:#x}..{:#x}"
.format(window, addr_range.start, addr_range.stop))
if window.data_width > self.data_width:
- raise ValueError("Window has data width {}, and cannot be added to a memory map "
+ raise ValueError("Window has data width {}, and cannot "
+ "be added to a memory map "
"with data width {}"
.format(window.data_width, self.data_width))
if window.data_width != self.data_width:
if sparse is None:
- raise ValueError("Address translation mode must be explicitly specified "
- "when adding a window with data width {} to a memory map "
+ raise ValueError("Address translation mode must be "
+ "explicitly specified "
+ "when adding a window with "
+ "data width {} to a memory map "
"with data width {}"
.format(window.data_width, self.data_width))
if not sparse and self.data_width % window.data_width != 0:
- raise ValueError("Dense addressing cannot be used because the memory map "
- "data width {} is not an integer multiple of window "
+ raise ValueError("Dense addressing cannot be used "
+ "because the memory map "
+ "data width {} is not an integer "
+ "multiple of window "
"data width {}"
.format(self.data_width, window.data_width))
# a window can still be aligned using align_to().
alignment = max(self.alignment, window.addr_width // ratio)
- addr_range = self._compute_addr_range(addr, size, ratio, alignment=alignment)
+ addr_range = self._compute_addr_range(
+ addr, size, ratio, alignment=alignment)
self._ranges.insert(addr_range, window)
self._windows[window] = addr_range
self._next_addr = addr_range.stop
wider bus. Otherwise, it is always 1.
"""
for window, window_range in self._windows.items():
- yield window, (window_range.start, window_range.stop, window_range.step)
+ yield window, (window_range.start, window_range.stop,
+ window_range.step)
def window_patterns(self):
"""Iterate local windows and patterns that match their address ranges.
it is always 1.
"""
for window, window_range in self._windows.items():
- pattern = "{:0{}b}{}".format(window_range.start >> window.addr_width,
+ pattern = "{:0{}b}{}".format((window_range.start >>
+ window.addr_width),
self.addr_width - window.addr_width,
"-" * window.addr_width)
yield window, (pattern, window_range.step)
# Accessing a resource through a dense and then a sparse window results in very strange
# layouts that cannot be easily represented, so reject those.
assert window_range.step == 1 or width == window.data_width
- size = (end - start) // window_range.step
+ size = (end - start) // window_range.step
start += window_range.start
width *= window_range.step
return start, start + size, width
"""
for addr_range, assignment in self._ranges.items():
if assignment in self._resources:
- yield assignment, (addr_range.start, addr_range.stop, self.data_width)
+ yield assignment, (addr_range.start, addr_range.stop,
+ self.data_width)
elif assignment in self._windows:
for sub_resource, sub_descr in assignment.all_resources():
- yield sub_resource, self._translate(*sub_descr, assignment, addr_range)
+ yield sub_resource, self._translate(*sub_descr,
+ assignment,
+ addr_range)
else:
- assert False # :nocov:
+ assert False # :nocov:
def find_resource(self, resource):
"""Find address range corresponding to a resource.
for window, window_range in self._windows.items():
try:
- return self._translate(*window.find_resource(resource), window, window_range)
+ return self._translate(*window.find_resource(resource),
+ window,
+ window_range)
except KeyError:
pass
return assignment
elif assignment in self._windows:
addr_range = self._windows[assignment]
- return assignment.decode_address((address - addr_range.start) // addr_range.step)
+ return assignment.decode_address(
+ (address - addr_range.start) // addr_range.step)
else:
- assert False # :nocov:
+ assert False # :nocov: