Eunchan Kim | c745294 | 2019-12-19 17:04:37 -0800 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | |
Eunchan Kim | c745294 | 2019-12-19 17:04:37 -0800 | [diff] [blame] | 5 | import logging as log |
| 6 | |
| 7 | |
| 8 | def is_pow2(v): |
| 9 | """Return true if value is power of two |
| 10 | """ |
| 11 | if not isinstance(v, int): |
| 12 | log.warning("is_pow2 received non-integer value {}".format(v)) |
| 13 | return False |
| 14 | t = 1 |
| 15 | while t <= v: |
| 16 | if t == v: |
| 17 | return True |
| 18 | t = t * 2 |
| 19 | |
| 20 | return False |
Eunchan Kim | eeea1f4 | 2020-01-13 10:26:10 -0800 | [diff] [blame] | 21 | |
| 22 | |
| 23 | def simplify_addr(dev, xbar): |
| 24 | """Make smaller entries by combining them |
| 25 | |
| 26 | If any contiguous regions exist, concatenate them. |
| 27 | For instance, 0x1000 ~ 0x1FFF , 0x2000~ 0x2FFF ==> 0x1000 ~ 0x2FFF |
| 28 | |
| 29 | It also checks if there's no device between the gap, then merge |
| 30 | the ranges. For instance: |
| 31 | |
| 32 | {0x4000_0000, 0x1_0000}, {0x4008_0000, 0x1_0000} then it combines two |
| 33 | entries into {0x4000_0000, 0x9_0000} |
| 34 | |
| 35 | @param addrs List of Dict[Addr] : {'base_addr':,'size_byte':} |
| 36 | """ |
| 37 | |
| 38 | addrs = dev["addr_range"] |
| 39 | # Sort based on the base addr |
| 40 | newlist = sorted(addrs, key=lambda k: int(k['base_addr'], 0)) |
| 41 | # check if overlap or contiguous |
| 42 | result = [] |
| 43 | for e in newlist: |
| 44 | if len(result) == 0: |
| 45 | result.append(e) |
| 46 | continue |
| 47 | # if contiguous |
| 48 | if int(e["base_addr"], 0) == int(result[-1]["base_addr"], 0) + int( |
| 49 | result[-1]["size_byte"], 0): |
| 50 | # update previous entry size |
| 51 | result[-1]["size_byte"] = "0x{:x}".format( |
| 52 | int(result[-1]["size_byte"], 0) + int(e["size_byte"], 0)) |
| 53 | continue |
| 54 | |
| 55 | if no_device_in_range(xbar, dev["name"], result[-1], e): |
| 56 | # Determine if size can be power of 2 value |
| 57 | smallest_addr_gte = get_next_base_addr(e["base_addr"], xbar, |
| 58 | dev["name"]) |
| 59 | |
| 60 | # Choose next value |
| 61 | if smallest_addr_gte == -1: |
| 62 | next_value = 0x100000000 |
| 63 | else: |
| 64 | next_value = int(smallest_addr_gte["base_addr"], 0) |
| 65 | |
| 66 | calc_size = int(e["base_addr"], 0) + int(e["size_byte"], 0) - int( |
| 67 | result[-1]["base_addr"], 0) |
| 68 | |
| 69 | # find power of 2 if possible |
| 70 | size_byte = find_pow2_size(result[-1], calc_size, next_value) |
| 71 | |
| 72 | result[-1]["size_byte"] = "0x{:x}".format(size_byte) |
| 73 | continue |
| 74 | |
| 75 | # If overlapping (Should it be consider? TlGen will catch it) |
| 76 | |
| 77 | # Normal case |
| 78 | result.append(e) |
| 79 | |
| 80 | # return result |
| 81 | return result |
| 82 | |
| 83 | |
| 84 | def no_device_in_range(xbar, name, f, t): |
| 85 | """Check if other devices doesn't overlap with the range 'from <= x < to' |
| 86 | """ |
| 87 | from_addr = int(f["base_addr"], 0) + int(f["size_byte"], 0) |
| 88 | to_addr = int(t["base_addr"], 0) |
| 89 | |
| 90 | for node in [ |
| 91 | x for x in xbar["nodes"] |
| 92 | if x["type"] == "device" and not x["name"] == name |
| 93 | ]: |
Eunchan Kim | 837c796 | 2020-04-30 12:15:49 -0700 | [diff] [blame] | 94 | if "addr_range" not in node: |
Eunchan Kim | eeea1f4 | 2020-01-13 10:26:10 -0800 | [diff] [blame] | 95 | # Xbar? |
| 96 | log.info("Xbar type node cannot be compared in this version.", |
| 97 | "Please use in caution") |
| 98 | continue |
| 99 | assert isinstance(node["addr_range"], list) |
| 100 | |
| 101 | for addr in node["addr_range"]: |
| 102 | b_addr = int(addr["base_addr"], 0) |
| 103 | e_addr = b_addr + int(addr["size_byte"], 0) |
| 104 | |
| 105 | if e_addr <= from_addr or b_addr >= to_addr: |
| 106 | # No overlap |
| 107 | continue |
| 108 | return False |
| 109 | return True |
| 110 | |
| 111 | |
| 112 | def get_next_base_addr(addr, xbar, name): |
| 113 | """Return the least value of base_addr of the IP greater than addr |
| 114 | |
| 115 | """ |
| 116 | if isinstance(addr, str): |
| 117 | value = int(addr, 0) |
| 118 | else: |
| 119 | assert isinstance(addr, int) |
| 120 | value = addr |
| 121 | |
| 122 | device_list = [ |
| 123 | x for x in xbar["nodes"] |
| 124 | if x["type"] == "device" and not x["name"] == name |
| 125 | ] |
| 126 | |
| 127 | try: |
| 128 | addrs = [a for r in device_list for a in r["addr_range"]] |
| 129 | except KeyError: |
| 130 | log.error("Address range is wrong.\n {}".format( |
Eunchan Kim | 837c796 | 2020-04-30 12:15:49 -0700 | [diff] [blame] | 131 | [x for x in device_list if "addr_range" not in x])) |
Eunchan Kim | eeea1f4 | 2020-01-13 10:26:10 -0800 | [diff] [blame] | 132 | raise SystemExit() |
| 133 | |
| 134 | sorted_list = sorted(addrs, key=lambda k: int(k["base_addr"], 0)) |
| 135 | |
| 136 | gte_list = [x for x in sorted_list if int(x["base_addr"], 0) > value] |
| 137 | |
| 138 | if len(gte_list) == 0: |
| 139 | return -1 |
| 140 | |
| 141 | return gte_list[0] |
| 142 | |
| 143 | |
| 144 | def find_pow2_size(addr, min_size, next_value): |
| 145 | """Find smallest power of 2 value greater than min_size by given addr. |
| 146 | |
| 147 | For instance, {addr:0x4000_0000, min_size:0x21000} and `next_value` as |
| 148 | 0x40080000, the result will be 0x4_0000 |
| 149 | |
| 150 | But it should return result not exceeding the base_addr's leading one bit |
| 151 | position. For instance, if the base_addr is 0x4003_0000, the return value |
| 152 | should be less than or equal to 0x1_0000. Cannot be 0x4_0000. So, this |
| 153 | case, the function returns the original min_size value 0x21000. |
| 154 | """ |
| 155 | base_addr = int(addr["base_addr"], 0) |
| 156 | |
| 157 | diff = next_value - base_addr |
| 158 | |
| 159 | # Find the least one bit position. |
| 160 | # If base_addr is 0, then any value can be used |
| 161 | if not base_addr == 0: |
| 162 | leading_one = 1 |
| 163 | while True: |
| 164 | if base_addr & leading_one != 0: |
| 165 | break |
| 166 | leading_one = leading_one << 1 |
| 167 | |
| 168 | if leading_one <= diff: |
| 169 | diff = leading_one |
| 170 | |
| 171 | i = 1 |
| 172 | while True: |
| 173 | i = i << 1 |
| 174 | if i >= min_size: |
| 175 | break |
| 176 | |
| 177 | # If found pow2 value is greater than diff, it cannot be used. Just use |
| 178 | # min_size then the tool will use comparators (>=, <=) |
| 179 | if i > diff: |
| 180 | i = min_size |
| 181 | |
| 182 | # Shall be greater than 4kB |
| 183 | assert i >= 0x1000 |
| 184 | |
| 185 | return i |
Weicai Yang | 3a2d0bc | 2021-08-25 15:41:41 -0700 | [diff] [blame] | 186 | |
| 187 | |
| 188 | def get_toggle_excl_bits(addr_ranges, addr_width=32): |
| 189 | """ Input addr_ranges is a list of (start_addr, end_addr) |
| 190 | From given addr_ranges, will calculate what address bits can't be toggled as |
| 191 | only the address in the ranges can pass through the xbar to the device |
| 192 | """ |
| 193 | excl_bits = [] # list of (start_bit, end_bit) |
| 194 | |
| 195 | # Find all the bits that can be toggled to 1 |
| 196 | toggle_bits = 0 |
| 197 | for addr in addr_ranges: |
| 198 | # The size of the addres range should be power of 2 |
| 199 | assert is_power_of_two(addr[1] - addr[0] + 1) |
| 200 | |
| 201 | toggle_bits |= addr[0] |
| 202 | toggle_bits |= addr[1] - addr[0] |
| 203 | |
| 204 | # Assume toggle_bits = 010011, generate below as bit 2, 3, 5 are never toggled |
| 205 | # excl_bits = [(5,5), (2,3)] |
| 206 | start_bit = -1 |
| 207 | for i in range(addr_width): |
| 208 | bit = toggle_bits & 1 |
| 209 | if not bit and start_bit == -1: |
| 210 | start_bit = i |
| 211 | elif bit and start_bit != -1: |
| 212 | excl_bits.append((start_bit, i - 1)) |
| 213 | start_bit = -1 |
| 214 | |
| 215 | toggle_bits = toggle_bits >> 1 |
| 216 | |
| 217 | # Handle tailing zero, which are also never toggled |
| 218 | if start_bit != -1: |
| 219 | excl_bits.append((start_bit, addr_width - 1)) |
| 220 | |
| 221 | return excl_bits |
| 222 | |
| 223 | |
| 224 | def is_power_of_two(x): |
| 225 | """Function to check if x is power of 2 |
| 226 | """ |
| 227 | return (x and (not (x & (x - 1)))) |