| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| import logging as log |
| |
| |
| def is_pow2(v): |
| """Return true if value is power of two |
| """ |
| if not isinstance(v, int): |
| log.warning("is_pow2 received non-integer value {}".format(v)) |
| return False |
| t = 1 |
| while t <= v: |
| if t == v: |
| return True |
| t = t * 2 |
| |
| return False |
| |
| |
| def simplify_addr(dev, xbar): |
| """Make smaller entries by combining them |
| |
| If any contiguous regions exist, concatenate them. |
| For instance, 0x1000 ~ 0x1FFF , 0x2000~ 0x2FFF ==> 0x1000 ~ 0x2FFF |
| |
| It also checks if there's no device between the gap, then merge |
| the ranges. For instance: |
| |
| {0x4000_0000, 0x1_0000}, {0x4008_0000, 0x1_0000} then it combines two |
| entries into {0x4000_0000, 0x9_0000} |
| |
| @param addrs List of Dict[Addr] : {'base_addr':,'size_byte':} |
| """ |
| |
| addrs = dev["addr_range"] |
| # Sort based on the base addr |
| newlist = sorted(addrs, key=lambda k: int(k['base_addr'], 0)) |
| # check if overlap or contiguous |
| result = [] |
| for e in newlist: |
| if len(result) == 0: |
| result.append(e) |
| continue |
| # if contiguous |
| if int(e["base_addr"], 0) == int(result[-1]["base_addr"], 0) + int( |
| result[-1]["size_byte"], 0): |
| # update previous entry size |
| result[-1]["size_byte"] = "0x{:x}".format( |
| int(result[-1]["size_byte"], 0) + int(e["size_byte"], 0)) |
| continue |
| |
| if no_device_in_range(xbar, dev["name"], result[-1], e): |
| # Determine if size can be power of 2 value |
| smallest_addr_gte = get_next_base_addr(e["base_addr"], xbar, |
| dev["name"]) |
| |
| # Choose next value |
| if smallest_addr_gte == -1: |
| next_value = 0x100000000 |
| else: |
| next_value = int(smallest_addr_gte["base_addr"], 0) |
| |
| calc_size = int(e["base_addr"], 0) + int(e["size_byte"], 0) - int( |
| result[-1]["base_addr"], 0) |
| |
| # find power of 2 if possible |
| size_byte = find_pow2_size(result[-1], calc_size, next_value) |
| |
| result[-1]["size_byte"] = "0x{:x}".format(size_byte) |
| continue |
| |
| # If overlapping (Should it be consider? TlGen will catch it) |
| |
| # Normal case |
| result.append(e) |
| |
| # return result |
| return result |
| |
| |
| def no_device_in_range(xbar, name, f, t): |
| """Check if other devices doesn't overlap with the range 'from <= x < to' |
| """ |
| from_addr = int(f["base_addr"], 0) + int(f["size_byte"], 0) |
| to_addr = int(t["base_addr"], 0) |
| |
| for node in [ |
| x for x in xbar["nodes"] |
| if x["type"] == "device" and not x["name"] == name |
| ]: |
| if "addr_range" not in node: |
| # Xbar? |
| log.info("Xbar type node cannot be compared in this version.", |
| "Please use in caution") |
| continue |
| assert isinstance(node["addr_range"], list) |
| |
| for addr in node["addr_range"]: |
| b_addr = int(addr["base_addr"], 0) |
| e_addr = b_addr + int(addr["size_byte"], 0) |
| |
| if e_addr <= from_addr or b_addr >= to_addr: |
| # No overlap |
| continue |
| return False |
| return True |
| |
| |
| def get_next_base_addr(addr, xbar, name): |
| """Return the least value of base_addr of the IP greater than addr |
| |
| """ |
| if isinstance(addr, str): |
| value = int(addr, 0) |
| else: |
| assert isinstance(addr, int) |
| value = addr |
| |
| device_list = [ |
| x for x in xbar["nodes"] |
| if x["type"] == "device" and not x["name"] == name |
| ] |
| |
| try: |
| addrs = [a for r in device_list for a in r["addr_range"]] |
| except KeyError: |
| log.error("Address range is wrong.\n {}".format( |
| [x for x in device_list if "addr_range" not in x])) |
| raise SystemExit() |
| |
| sorted_list = sorted(addrs, key=lambda k: int(k["base_addr"], 0)) |
| |
| gte_list = [x for x in sorted_list if int(x["base_addr"], 0) > value] |
| |
| if len(gte_list) == 0: |
| return -1 |
| |
| return gte_list[0] |
| |
| |
| def find_pow2_size(addr, min_size, next_value): |
| """Find smallest power of 2 value greater than min_size by given addr. |
| |
| For instance, {addr:0x4000_0000, min_size:0x21000} and `next_value` as |
| 0x40080000, the result will be 0x4_0000 |
| |
| But it should return result not exceeding the base_addr's leading one bit |
| position. For instance, if the base_addr is 0x4003_0000, the return value |
| should be less than or equal to 0x1_0000. Cannot be 0x4_0000. So, this |
| case, the function returns the original min_size value 0x21000. |
| """ |
| base_addr = int(addr["base_addr"], 0) |
| |
| diff = next_value - base_addr |
| |
| # Find the least one bit position. |
| # If base_addr is 0, then any value can be used |
| if not base_addr == 0: |
| leading_one = 1 |
| while True: |
| if base_addr & leading_one != 0: |
| break |
| leading_one = leading_one << 1 |
| |
| if leading_one <= diff: |
| diff = leading_one |
| |
| i = 1 |
| while True: |
| i = i << 1 |
| if i >= min_size: |
| break |
| |
| # If found pow2 value is greater than diff, it cannot be used. Just use |
| # min_size then the tool will use comparators (>=, <=) |
| if i > diff: |
| i = min_size |
| |
| # Minimum size is one 32bit register. |
| assert i >= 0x4 |
| |
| return i |
| |
| |
| def get_toggle_excl_bits(addr_ranges, addr_width=32): |
| """ Input addr_ranges is a list of (start_addr, end_addr) |
| From given addr_ranges, will calculate what address bits can't be toggled as |
| only the address in the ranges can pass through the xbar to the device |
| """ |
| excl_bits = [] # list of (start_bit, end_bit) |
| |
| # Find all the bits that can be toggled to 1 |
| toggle_bits = 0 |
| for addr in addr_ranges: |
| # The size of the addres range should be power of 2 |
| assert is_power_of_two(addr[1] - addr[0] + 1) |
| |
| toggle_bits |= addr[0] |
| toggle_bits |= addr[1] - addr[0] |
| |
| # Assume toggle_bits = 010011, generate below as bit 2, 3, 5 are never toggled |
| # excl_bits = [(5,5), (2,3)] |
| start_bit = -1 |
| for i in range(addr_width): |
| bit = toggle_bits & 1 |
| if not bit and start_bit == -1: |
| start_bit = i |
| elif bit and start_bit != -1: |
| excl_bits.append((start_bit, i - 1)) |
| start_bit = -1 |
| |
| toggle_bits = toggle_bits >> 1 |
| |
| # Handle tailing zero, which are also never toggled |
| if start_bit != -1: |
| excl_bits.append((start_bit, addr_width - 1)) |
| |
| return excl_bits |
| |
| |
| def is_power_of_two(x): |
| """Function to check if x is power of 2 |
| """ |
| return (x and (not (x & (x - 1)))) |