| # 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 |
| from copy import deepcopy |
| from functools import partial |
| |
| from .lib import * |
| import hjson |
| |
| |
| def amend_ip(top, ip): |
| """ Amend additional information into top module |
| |
| Amended fields: |
| - size: register space |
| - clock: converted into ip_clock |
| - bus_device |
| - bus_host: none if doesn't exist |
| - available_input_list: empty list if doesn't exist |
| - available_output_list: empty list if doesn't exist |
| - available_inout_list: empty list if doesn't exist |
| - interrupt_list: empty list if doesn't exist |
| - alert_list: empty list if doesn't exist |
| """ |
| ip_list_in_top = [x["name"].lower() for x in top["module"]] |
| ipname = ip["name"].lower() |
| if not ipname in ip_list_in_top: |
| log.info("TOP doens't use the IP %s. Skip" % ip["name"]) |
| return |
| |
| # Find index of the IP |
| ip_idx = ip_list_in_top.index(ipname) |
| # Needed to detect async alert transitions below |
| ah_idx = ip_list_in_top.index("alert_handler") |
| |
| ip_module = top["module"][ip_idx] |
| |
| # Size |
| if not "size" in ip_module: |
| ip_module["size"] = "0x%x" % max(ip["gensize"], 0x1000) |
| elif ip_module["size"] < ip["gensize"]: |
| log.error( |
| "given 'size' field in IP %s is smaller than the required space" % |
| ip_module["name"]) |
| |
| # bus_device |
| ip_module["bus_device"] = ip["bus_device"] |
| |
| # bus_host |
| if "bus_host" in ip and ip["bus_host"] != "": |
| ip_module["bus_host"] = ip["bus_host"] |
| else: |
| ip_module["bus_host"] = "none" |
| |
| # available_input_list , available_output_list, available_inout_list |
| if "available_input_list" in ip: |
| ip_module["available_input_list"] = ip["available_input_list"] |
| for i in ip_module["available_input_list"]: |
| i.pop('desc', None) |
| i["type"] = "input" |
| i["width"] = int(i["width"]) |
| else: |
| ip_module["available_input_list"] = [] |
| if "available_output_list" in ip: |
| ip_module["available_output_list"] = ip["available_output_list"] |
| for i in ip_module["available_output_list"]: |
| i.pop('desc', None) |
| i["type"] = "output" |
| i["width"] = int(i["width"]) |
| else: |
| ip_module["available_output_list"] = [] |
| if "available_inout_list" in ip: |
| ip_module["available_inout_list"] = ip["available_inout_list"] |
| for i in ip_module["available_inout_list"]: |
| i.pop('desc', None) |
| i["type"] = "inout" |
| i["width"] = int(i["width"]) |
| else: |
| ip_module["available_inout_list"] = [] |
| |
| # interrupt_list |
| if "interrupt_list" in ip: |
| ip_module["interrupt_list"] = ip["interrupt_list"] |
| for i in ip_module["interrupt_list"]: |
| i.pop('desc', None) |
| i["type"] = "interrupt" |
| i["width"] = int(i["width"]) |
| else: |
| ip_module["interrupt_list"] = [] |
| |
| # alert_list |
| if "alert_list" in ip: |
| ip_module["alert_list"] = ip["alert_list"] |
| for i in ip_module["alert_list"]: |
| i.pop('desc', None) |
| i["type"] = "alert" |
| i["width"] = int(i["width"]) |
| # automatically insert asynchronous transition if necessary |
| if ip_module["clock_connections"]["clk_i"] == \ |
| top["module"][ah_idx]["clock_connections"]["clk_i"]: |
| i["async"] = 0 |
| else: |
| i["async"] = 1 |
| else: |
| ip_module["alert_list"] = [] |
| |
| # scan |
| if "scan" in ip: |
| ip_module["scan"] = ip["scan"] |
| else: |
| ip_module["scan"] = "false" |
| |
| |
| # TODO: Replace this part to be configurable from Hjson or template |
| predefined_modules = { |
| "corei": "rv_core_ibex", |
| "cored": "rv_core_ibex", |
| "dm_sba": "rv_dm", |
| "debug_mem": "rv_dm" |
| } |
| |
| |
| def is_xbar(top, name): |
| """Check if the given name is crossbar |
| """ |
| xbars = list(filter(lambda node: node["name"] == name, top["xbar"])) |
| if len(xbars) == 0: |
| return False, None |
| |
| if len(xbars) > 1: |
| log.error("Matching crossbar {} is more than one.".format(name)) |
| raise SystemExit() |
| |
| return True, xbars[0] |
| |
| |
| def xbar_addhost(top, xbar, host): |
| """Add host nodes information |
| |
| - xbar: bool, true if the host port is from another Xbar |
| """ |
| # Check and fetch host if exists in nodes |
| obj = list(filter(lambda node: node["name"] == host, xbar["nodes"])) |
| if len(obj) == 0: |
| log.warning( |
| "host %s doesn't exist in the node list. Using default values" % |
| host) |
| obj = { |
| "name": host, |
| "clock": xbar['clock'], |
| "reset": xbar['reset'], |
| "type": "host", |
| "inst_type": "", |
| # The default matches RTL default |
| # pipeline_byp is don't care if pipeline is false |
| "pipeline": "true", |
| "pipeline_byp": "true" |
| } |
| topxbar["nodes"].append(obj) |
| return |
| |
| xbar_bool, xbar_h = is_xbar(top, host) |
| if xbar_bool: |
| log.info("host {} is a crossbar. Nothing to deal with.".format(host)) |
| |
| obj[0]["xbar"] = xbar_bool |
| |
| if 'clock' not in obj[0]: |
| obj[0]["clock"] = xbar['clock'] |
| |
| if 'reset' not in obj[0]: |
| obj[0]["reset"] = xbar["reset"] |
| |
| obj[0]["inst_type"] = predefined_modules[ |
| host] if host in predefined_modules else "" |
| obj[0]["pipeline"] = obj[0]["pipeline"] if "pipeline" in obj[0] else "true" |
| obj[0]["pipeline_byp"] = obj[0]["pipeline_byp"] if obj[0][ |
| "pipeline"] == "true" and "pipeline_byp" in obj[0] else "true" |
| |
| |
| def process_pipeline_var(node): |
| """Add device nodes pipeline / pipeline_byp information |
| |
| - Supply a default of true / true if not defined by xbar |
| """ |
| node["pipeline"] = node["pipeline"] if "pipeline" in node else "true" |
| node["pipeline_byp"] = node[ |
| "pipeline_byp"] if "pipeline_byp" in node else "true" |
| |
| |
| def xbar_adddevice(top, xbar, device): |
| """Add device nodes information |
| |
| - clock: comes from module if exist, use xbar default otherwise |
| - reset: comes from module if exist, use xbar default otherwise |
| - inst_type: comes from module or memory if exist. |
| - base_addr: comes from module or memory, or assume rv_plic? |
| - size_byte: comes from module or memory |
| - xbar: bool, true if the device port is another xbar |
| """ |
| deviceobj = list( |
| filter(lambda node: node["name"] == device, |
| top["module"] + top["memory"])) |
| nodeobj = list(filter(lambda node: node["name"] == device, xbar["nodes"])) |
| |
| xbar_list = [x["name"] for x in top["xbar"] if x["name"] != xbar["name"]] |
| |
| # case 1: another xbar --> check in xbar list |
| if device in xbar_list and len(nodeobj) == 0: |
| log.error( |
| "Another crossbar %s needs to be specified in the 'nodes' list" % |
| device) |
| return |
| |
| if len(deviceobj) == 0: |
| # doesn't exist, |
| |
| # case 1: Crossbar handling |
| if device in xbar_list: |
| log.warning( |
| "device {} in Xbar {} is connected to another Xbar".format( |
| device, xbar["name"])) |
| assert len(nodeobj) == 1 |
| nodeobj[0]["xbar"] = True |
| process_pipeline_var(nodeobj[0]) |
| return |
| |
| # case 2: predefined_modules (debug_mem, rv_plic) |
| # TODO: Find configurable solution not from predefined but from object? |
| if device in predefined_modules: |
| if device == "debug_mem": |
| if len(nodeobj) == 0: |
| # Add new debug_mem |
| xbar["nodes"].append({ |
| "name": "debug_mem", |
| "type": "device", |
| "clock": xbar['clock'], |
| "reset": xbar['reset'], |
| "inst_type": predefined_modules["debug_mem"], |
| "addr_range": [{ |
| "base_addr": top["debug_mem_base_addr"], |
| "size_byte": "0x1000", |
| }], |
| "xbar": False, |
| "pipeline" : "true", |
| "pipeline_byp" : "true" |
| }) # yapf: disable |
| else: |
| # Update if exists |
| node = nodeobj[0] |
| node["inst_type"] = predefined_modules["debug_mem"] |
| node["addr_range"] = [{ |
| "base_addr": |
| top["debug_mem_base_addr"], |
| "size_byte": |
| "0x1000" |
| }] |
| node["xbar"] = False |
| process_pipeline_var(node) |
| else: |
| log.error("device %s shouldn't be host type" % device) |
| return |
| # case 3: not defined |
| else: |
| # Crossbar check |
| log.error( |
| "device %s doesn't exist in 'module', 'memory', or predefined" |
| % device) |
| return |
| |
| # Search object from module or memory |
| elif len(nodeobj) == 0: |
| # found in module or memory but node object doesn't exist. |
| xbar["nodes"].append({ |
| "name" : device, |
| "type" : "device", |
| "clock" : deviceobj[0]["clock"], |
| "reset" : deviceobj[0]["reset"], |
| "inst_type" : deviceobj[0]["type"], |
| "addr_range": [{"base_addr" : deviceobj[0]["base_addr"], |
| "size_byte": deviceobj[0]["size"]}], |
| "pipeline" : "true", |
| "pipeline_byp" : "true", |
| "xbar" : True if device in xbar_list else False |
| }) # yapf: disable |
| |
| else: |
| # found and exist in the nodes too |
| node = nodeobj[0] |
| node["inst_type"] = deviceobj[0]["type"] |
| node["addr_range"] = [{ |
| "base_addr": deviceobj[0]["base_addr"], |
| "size_byte": deviceobj[0]["size"] |
| }] |
| node["xbar"] = True if device in xbar_list else False |
| process_pipeline_var(node) |
| |
| |
| def amend_xbar(top, xbar): |
| """Amend crossbar informations to the top list |
| |
| Amended fields |
| - clock: Adopt from module clock if exists |
| - inst_type: Module instance some module will be hard-coded |
| the tool searches module list and memory list then put here |
| - base_addr: from top["module"] |
| - size: from top["module"] |
| """ |
| xbar_list = [x["name"] for x in top["xbar"]] |
| if not xbar["name"] in xbar_list: |
| log.info( |
| "Xbar %s doesn't belong to the top %s. Check if the xbar doesn't need" |
| % (xbar["name"], top["name"])) |
| return |
| |
| topxbar = list( |
| filter(lambda node: node["name"] == xbar["name"], top["xbar"]))[0] |
| |
| topxbar["connections"] = deepcopy(xbar["connections"]) |
| if "nodes" in xbar: |
| topxbar["nodes"] = deepcopy(xbar["nodes"]) |
| else: |
| topxbar["nodes"] = [] |
| |
| # xbar primary clock and reset |
| topxbar["clock"] = xbar["clock_primary"] |
| topxbar["reset"] = xbar["reset_primary"] |
| |
| # Build nodes from 'connections' |
| device_nodes = set() |
| for host, devices in xbar["connections"].items(): |
| # add host first |
| xbar_addhost(top, topxbar, host) |
| |
| # add device if doesn't exist |
| device_nodes.update(devices) |
| |
| log.info(device_nodes) |
| for device in device_nodes: |
| xbar_adddevice(top, topxbar, device) |
| |
| |
| def xbar_cross(xbar, xbars): |
| """Check if cyclic dependency among xbars |
| |
| And gather the address range for device port (to another Xbar) |
| |
| @param node_name if not "", the function only search downstream |
| devices starting from the node_name |
| @param visited The nodes it visited to reach this port. If any |
| downstream port from node_name in visited, it means |
| circular path exists. It should be fatal error. |
| """ |
| # Step 1: Visit devices (gather the address range) |
| log.info("Processing circular path check for {}".format(xbar["name"])) |
| addr = [] |
| for node in [ |
| x for x in xbar["nodes"] |
| if x["type"] == "device" and "xbar" in x and x["xbar"] == False |
| ]: |
| addr.extend(node["addr_range"]) |
| |
| # Step 2: visit xbar device ports |
| xbar_nodes = [ |
| x for x in xbar["nodes"] |
| if x["type"] == "device" and "xbar" in x and x["xbar"] == True |
| ] |
| |
| # Now call function to get the device range |
| # the node["name"] is used to find the host_xbar and its connection. The |
| # assumption here is that there's only one connection from crossbar A to |
| # crossbar B. |
| # |
| # device_xbar is the crossbar has a device port with name as node["name"]. |
| # host_xbar is the crossbar has a host port with name as node["name"]. |
| for node in xbar_nodes: |
| xbar_addr = xbar_cross_node(node["name"], xbar, xbars, visited=[]) |
| node["addr_range"] = xbar_addr |
| |
| |
| def xbar_cross_node(node_name, device_xbar, xbars, visited=[]): |
| # 1. Get the connected xbar |
| host_xbars = [x for x in xbars if x["name"] == node_name] |
| assert len(host_xbars) == 1 |
| host_xbar = host_xbars[0] |
| |
| log.info("Processing node {} in Xbar {}.".format(node_name, |
| device_xbar["name"])) |
| result = [] # [(base_addr, size), .. ] |
| # Sweep the devices using connections and gather the address. |
| # If the device is another xbar, call recursive |
| visited.append(host_xbar["name"]) |
| devices = host_xbar["connections"][device_xbar["name"]] |
| |
| for node in host_xbar["nodes"]: |
| if not node["name"] in devices: |
| continue |
| if "xbar" in node and node["xbar"] == True: |
| if not "addr_range" in node: |
| # Deeper dive into another crossbar |
| xbar_addr = xbar_cross_node(node["name"], host_xbar, xbars, |
| visited) |
| node["addr_range"] = xbar_addr |
| |
| result.extend(deepcopy(node["addr_range"])) |
| |
| visited.pop() |
| |
| return result |
| |
| |
| def simplify_xbar(xbars): |
| """ Simplify the address of xbar device port. |
| |
| It cannot be done without fully expanded addresses. |
| So, this should be done after adding all xbar addresses. |
| """ |
| |
| for xbar in xbars: |
| xdev_list = [ |
| x for x in xbar["nodes"] if x["type"] == "device" and x["xbar"] |
| ] |
| |
| for e in xdev_list: |
| e["addr_range"] = simplify_addr(e, xbar) |
| |
| |
| # TODO: Move to tlgen |
| def simplify_addr(dev, xbar): |
| """Reduce the number of entries smaller 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 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 not "addr_range" 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 not "addr_range" 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, (0x4000_0000, 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. |
| """ |
| 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 tha diff, it cannot be used. Just use |
| # min_size then the tool will use comparators (>=, <=) |
| if i > diff: |
| i = min_size |
| |
| # Shall be greater than 4kB |
| assert i >= 0x1000 |
| |
| return i |
| |
| |
| def amend_interrupt(top): |
| """Check interrupt_module if exists, or just use all modules |
| """ |
| if not "interrupt_module" in top: |
| top["interrupt_module"] = [x["name"] for x in top["module"]] |
| |
| if not "interrupt" in top or top["interrupt"] == "": |
| top["interrupt"] = [] |
| |
| for m in top["interrupt_module"]: |
| ip = list(filter(lambda module: module["name"] == m, top["module"])) |
| if len(ip) == 0: |
| log.warning( |
| "Cannot find IP %s which is used in the interrupt_module" % m) |
| continue |
| |
| log.info("Adding interrupts from module %s" % ip[0]["name"]) |
| top["interrupt"] += list( |
| map(partial(add_prefix_to_signal, prefix=m.lower()), |
| ip[0]["interrupt_list"])) |
| |
| |
| def amend_alert(top): |
| """Check interrupt_module if exists, or just use all modules |
| """ |
| if not "alert_module" in top: |
| top["alert_module"] = [x["name"] for x in top["module"]] |
| |
| if not "alert" in top or top["alert"] == "": |
| top["alert"] = [] |
| |
| for m in top["alert_module"]: |
| ip = list(filter(lambda module: module["name"] == m, top["module"])) |
| if len(ip) == 0: |
| log.warning("Cannot find IP %s which is used in the alert_module" % |
| m) |
| continue |
| |
| log.info("Adding alert from module %s" % ip[0]["name"]) |
| top["alert"] += list( |
| map(partial(add_prefix_to_signal, prefix=m.lower()), |
| ip[0]["alert_list"])) |
| |
| |
| def amend_pinmux_io(top): |
| """ Check dio_modules/ mio_modules. If not exists, add all modules to mio |
| """ |
| pinmux = top["pinmux"] |
| |
| if not "dio_modules" in pinmux: |
| pinmux['dio_modules'] = [] |
| |
| # list out dedicated IO |
| pinmux['dio'] = [] |
| for e in pinmux["dio_modules"]: |
| # Check name if it is module or signal |
| mname, sname = get_ms_name(e["name"]) |
| |
| # Parse how many signals |
| m = get_module_by_name(top, mname) |
| |
| if sname != None: |
| signals = deepcopy([get_signal_by_name(m, sname)]) |
| else: |
| # Get all module signals |
| signals = deepcopy(m["available_input_list"] + |
| m["available_output_list"] + |
| m["available_inout_list"]) |
| |
| sig_width = sum([s["width"] for s in signals]) |
| |
| # convert signal with module name |
| signals = list( |
| map(partial(add_prefix_to_signal, prefix=mname), signals)) |
| # Parse how many pads are assigned |
| if not "pad" in e: |
| raise SystemExit("Should catch pad field in validate.py!") |
| |
| total_width = 0 |
| |
| # pads are the list of individual pin, each entry is 1 bit width |
| pads = [] |
| for p in e["pad"]: |
| pads += get_pad_list(p) |
| |
| # check if #sig and #pads are matched |
| if len(pads) != sig_width: |
| raise SystemExit("# Pads and # Sig (%s) aren't same: %d" % |
| (mname, sig_width)) |
| |
| # add info to pads["dio"] |
| for s in signals: |
| p = pads[:s["width"]] |
| pads = pads[s["width"]:] |
| s["pad"] = p |
| pinmux["dio"].append(s) |
| |
| dio_names = [p["name"] for p in pinmux["dio"]] |
| |
| ## Multiplexer IO |
| if not "mio_modules" in pinmux: |
| # Add all modules having available io to Multiplexer IO |
| pinmux["mio_modules"] = [] |
| |
| for m in top["module"]: |
| num_io = len(m["available_input_list"] + |
| m["available_output_list"] + |
| m["available_inout_list"]) |
| if num_io != 0: |
| # Add if not in dio_modules |
| pinmux["mio_modules"].append(m["name"]) |
| |
| # List up the dedicated IO to exclude from inputs/outputs |
| |
| # Add port list to `inputs` and `outputs` fields |
| if not "inputs" in pinmux: |
| pinmux["inputs"] = [] |
| if not "outputs" in pinmux: |
| pinmux["outputs"] = [] |
| if not "inouts" in pinmux: |
| pinmux["inouts"] = [] |
| |
| for e in pinmux["mio_modules"]: |
| tokens = e.split('.') |
| if len(tokens) not in [1, 2]: |
| raise SystemExit( |
| "Cannot parse signal/module in mio_modules {}".format(e)) |
| # Add all ports from the module to input/outputs |
| m = get_module_by_name(top, tokens[0]) |
| if m == None: |
| raise SystemExit("Module {} doesn't exist".format(tokens[0])) |
| |
| if len(tokens) == 1: |
| pinmux["inputs"] += list( |
| filter( |
| lambda x: x["name"] not in dio_names, |
| map( |
| partial(add_prefix_to_signal, |
| prefix=m["name"].lower()), |
| m["available_input_list"]))) |
| pinmux["outputs"] += list( |
| filter( |
| lambda x: x["name"] not in dio_names, |
| map( |
| partial(add_prefix_to_signal, |
| prefix=m["name"].lower()), |
| m["available_output_list"]))) |
| pinmux["inouts"] += list( |
| filter( |
| lambda x: x["name"] not in dio_names, |
| map( |
| partial(add_prefix_to_signal, |
| prefix=m["name"].lower()), |
| m["available_inout_list"]))) |
| |
| elif len(tokens) == 2: |
| # Current version doesn't consider signal in mio_modules |
| # only in dio_modules |
| raise SystemExit( |
| "Curren version doesn't support signal in mio_modules {}". |
| format(e)) |
| |
| |
| def merge_top(topcfg, ipobjs, xbarobjs): |
| gencfg = deepcopy(topcfg) |
| |
| # Combine ip cfg into topcfg |
| for ip in ipobjs: |
| amend_ip(gencfg, ip) |
| |
| # Combine the interrupt (should be processed prior to xbar) |
| amend_interrupt(gencfg) |
| |
| # Combine the alert (should be processed prior to xbar) |
| amend_alert(gencfg) |
| |
| # Creates input/output list in the pinmux |
| log.info("Processing PINMUX") |
| amend_pinmux_io(gencfg) |
| |
| # Combine xbar into topcfg |
| for xbar in xbarobjs: |
| amend_xbar(gencfg, xbar) |
| |
| # 2nd phase of xbar (gathering the devices address range) |
| for xbar in gencfg["xbar"]: |
| xbar_cross(xbar, gencfg["xbar"]) |
| |
| simplify_xbar(gencfg["xbar"]) |
| |
| # remove unwanted fields 'debug_mem_base_addr' |
| gencfg.pop('debug_mem_base_addr', None) |
| |
| return gencfg |