1# 2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7import functools 8 9import hardware.utils as utils 10 11 12@functools.total_ordering 13class Region: 14 ''' Represents a region of memory. ''' 15 16 def __init__(self, base: int, size: int, owner: 'WrappedNode'): 17 self.base = base 18 self.size = size 19 self.owner = owner 20 21 @staticmethod 22 def clone(other): 23 ret = Region(other.base, other.size) 24 return ret 25 26 def __repr__(self): 27 return 'Region(base=0x{:x},size=0x{:x})'.format(self.base, self.size) 28 29 def __eq__(self, other): 30 return self.base == other.base and self.size == other.size 31 32 def __ne__(self, other): 33 # Needed only for py2. 34 return not self.__eq__(other) 35 36 def __gt__(self, other): 37 return self.base > other.base 38 39 def __hash__(self): 40 return hash((self.base, self.size)) 41 42 @staticmethod 43 def from_range(start, end, owner): 44 ''' create a region from a start/end rather than start/size ''' 45 ret = Region(start, end - start, owner) 46 return ret 47 48 def overlaps(self, other): 49 ''' returns True if this region overlaps the given region ''' 50 # either our base is first, and to overlap our end must be > other.base 51 if self.base <= other.base and (self.base + self.size) > other.base: 52 return True 53 # or other.base is first, and to overlap other's end must be > self.base 54 elif other.base <= self.base and (other.base + other.size) > self.base: 55 return True 56 return False 57 58 def reserve(self, excluded): 59 ''' returns an array of regions that represent this region 60 minus the excluded range ''' 61 if not self.overlaps(excluded): 62 return [Region(self.base, self.size, self.owner)] 63 64 ret = [] 65 if self.base < excluded.base: 66 # the first region is from our base to excluded.base 67 ret.append(Region.from_range(self.base, excluded.base, self.owner)) 68 # skip the region from excluded.base - excluded.base + excluded.size 69 # if there's anything left, add it. 70 if (excluded.base + excluded.size) < (self.base + self.size): 71 ret.append(Region.from_range(excluded.base + excluded.size, 72 self.base + self.size, self.owner)) 73 else: # self.base >= excluded.base 74 # we skip the first chunk 75 # we add what's left after the current chunk. 76 if (self.base + self.size) > (excluded.base + excluded.size): 77 ret.append(Region.from_range(excluded.base + excluded.size, 78 self.base + self.size, self.owner)) 79 return ret 80 81 def align_base(self, align_bits): 82 ''' align this region up to a given number of bits ''' 83 new_base = utils.align_up(self.base, align_bits) 84 diff = new_base - self.base 85 new_size = self.size - diff 86 new = Region(new_base, new_size, self.owner) 87 return new 88 89 def align_size(self, align_bits): 90 ''' align this region's size to a given number of bits. 91 will move the base address down and the region's size 92 up ''' 93 new_base = utils.align_down(self.base, align_bits) 94 new_size = utils.align_up(self.size, align_bits) 95 new = Region(new_base, new_size, self.owner) 96 return new 97 98 def make_chunks(self, chunksz): 99 base = self.base 100 size = self.size 101 ret = [] 102 while size > 0: 103 ret.append(Region(base, min(size, chunksz), self.owner)) 104 base += chunksz 105 size -= chunksz 106 return ret 107