def autoconnect_xbar(topcfg: OrderedDict, xbar: OrderedDict): ports = [x for x in xbar["nodes"] if x["type"] in ["host", "device"]] for port in ports: if port["xbar"]: if port["type"] == "host": # Skip as device will add connection continue # Device port adds signal add_intermodule_connection(obj=topcfg, req_m=xbar["name"], req_s="tl_%s" % port["name"], rsp_m=port["name"], rsp_s="tl_%s" % xbar["name"]) continue # xbar port case # check if name exists in ["module", "memory"] ips = [ x for x in topcfg["module"] + topcfg["memory"] if x["name"] == port["name"] and lib.is_inst(x) ] assert len(ips) <= 1 if len(ips) == 0: # if not in module, memory, should be existed in top or ext field module_key = "{}.tl_{}".format(xbar["name"], port["name"]) if module_key not in topcfg["inter_module"]["top"] + list( topcfg["inter_module"]["external"].keys()): log.error("Inter-module key {} cannot be found in module, " "memory, top, or external lists.".format(module_key)) continue ip = ips[0] inter_signal_list = ip['inter_signal_list'] # get the port name def get_signame(act: str) -> OrderedDict: ims = [ x for x in inter_signal_list if (x.get('package') == 'tlul_pkg' and x['struct'] == 'tl' and x['act'] == act) ] return ims if port["type"] == "device": ims = get_signame("rsp") else: # host type ims = get_signame("req") assert len(ims) == 1 sig_name = ims[0]["name"] add_intermodule_connection(obj=topcfg, req_m=port["name"], req_s=sig_name, rsp_m=xbar["name"], rsp_s="tl_%s" % port["name"]) continue # len() == 1
def xbar_adddevice(top: Dict[str, object], name_to_block: Dict[str, IpBlock], xbar: Dict[str, object], other_xbars: List[str], device: str) -> None: """Add or amend an entry in xbar['nodes'] to represent the device interface - 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 - stub: There is no backing module / memory, instead a tlul port is created and forwarded above the current hierarchy """ device_parts = device.split('.', 1) device_base = device_parts[0] device_ifname = device_parts[1] if len(device_parts) > 1 else None # Try to find a block or memory instance with name device_base. Object # names should be unique, so there should never be more than one hit. instances = [ node for node in top["module"] + top["memory"] if node['name'] == device_base ] assert len(instances) <= 1 inst = instances[0] if instances else None # Try to find a node in the crossbar called device. Node names should be # unique, so there should never be more than one hit. nodes = [node for node in xbar['nodes'] if node['name'] == device] assert len(nodes) <= 1 node = nodes[0] if nodes else None log.info( "Handling xbar device {} (matches instance? {}; matches node? {})". format(device, inst is not None, node is not None)) # case 1: another xbar --> check in xbar list if node is None and device in other_xbars: log.error( "Another crossbar %s needs to be specified in the 'nodes' list" % device) return # If there is no module or memory with the right name, this might still be # ok: we might be connecting to another crossbar or to a predefined module. if inst is None: # case 1: Crossbar handling if device in other_xbars: log.info( "device {} in Xbar {} is connected to another Xbar".format( device, xbar["name"])) assert node is not None node["xbar"] = True node["stub"] = False process_pipeline_var(node) return # case 2: predefined_modules (debug_mem, rv_plic) # TODO: Find configurable solution not from predefined but from object? if device in predefined_modules: log.error("device %s shouldn't be host type" % device) return # case 3: not defined # Crossbar check log.error("Device %s doesn't exist in 'module', 'memory', predefined, " "or as a node object" % device) return # If we get here, inst points an instance of some block or memory. It # shouldn't point at a crossbar (because that would imply a naming clash) assert device_base not in other_xbars base_addr, size_byte = lib.get_base_and_size(name_to_block, inst, device_ifname) addr_range = {"base_addr": hex(base_addr), "size_byte": hex(size_byte)} stub = not lib.is_inst(inst) if node is None: log.error('Cannot connect to {!r} because ' 'the crossbar defines no node for {!r}.'.format( device, device_base)) return node["inst_type"] = inst["type"] node["addr_range"] = [addr_range] node["xbar"] = False node["stub"] = stub process_pipeline_var(node)
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 - stub: There is no backing module / memory, instead a tlul port is created and forwarded above the current hierarchy """ 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 log.info("Handling xbar device {}, devlen {}, nodelen {}".format( device, len(deviceobj), len(nodeobj))) 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.info( "device {} in Xbar {} is connected to another Xbar".format( device, xbar["name"])) assert len(nodeobj) == 1 nodeobj[0]["xbar"] = True nodeobj[0]["stub"] = False 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": [OrderedDict([ ("base_addr", top["debug_mem_base_addr"]), ("size_byte", "0x1000"), ])], "xbar": False, "stub": 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"] = [ OrderedDict([("base_addr", top["debug_mem_base_addr"]), ("size_byte", "0x1000")]) ] node["xbar"] = False node["stub"] = 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', predefined, or as a node object """ % 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": [OrderedDict([ ("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, "stub": not lib.is_inst(deviceobj[0]) }) # yapf: disable else: # found and exist in the nodes too node = nodeobj[0] node["inst_type"] = deviceobj[0]["type"] node["addr_range"] = [ OrderedDict([("base_addr", deviceobj[0]["base_addr"]), ("size_byte", deviceobj[0]["size"])]) ] node["xbar"] = True if device in xbar_list else False node["stub"] = not lib.is_inst(deviceobj[0]) process_pipeline_var(node)
def autoconnect_xbar(topcfg: OrderedDict, name_to_block: Dict[str, IpBlock], xbar: OrderedDict) -> None: # The crossbar is connecting to modules and memories in topcfg, plus # possible external connections. Make indices for the modules and memories # for quick lookup and add some assertions to make sure no name appears in # multiple places. name_to_module = {} for mod in topcfg['module']: assert mod['name'] not in name_to_module if lib.is_inst(mod): name_to_module[mod['name']] = mod name_to_memory = {} for mem in topcfg['memory']: assert mem['name'] not in name_to_memory if lib.is_inst(mem): name_to_memory[mem['name']] = mem # The names of modules and memories should be disjoint assert not (set(name_to_module.keys()) & set(name_to_memory.keys())) external_names = (set(topcfg['inter_module']['top']) | set(topcfg["inter_module"]["external"].keys())) ports = [x for x in xbar["nodes"] if x["type"] in ["host", "device"]] for port in ports: # Here, we expect port_name to either be a single identifier (in which # case, it's taken as the name of some module or memory) to be a dotted # pair MOD.INAME where MOD is the name of some module and INAME is the # associated interface name. name_parts = port['name'].split('.', 1) port_base = name_parts[0] port_iname = name_parts[1] if len(name_parts) > 1 else None esc_name = port['name'].replace('.', '__') if port["xbar"]: if port_iname is not None: log.error( 'A crossbar connection may not ' 'have a target of the form MOD.INAME (saw {!r})'.format( port['name'])) continue if port["type"] == "host": # Skip as device will add connection continue # Device port adds signal add_intermodule_connection(obj=topcfg, req_m=xbar["name"], req_s="tl_" + esc_name, rsp_m=esc_name, rsp_s="tl_" + xbar["name"]) continue # xbar port case port_mod = name_to_module.get(port_base) port_mem = name_to_memory.get(port_base) assert port_mod is None or port_mem is None if not (port_mod or port_mem): # if not in module, memory, should be existed in top or ext field module_key = "{}.tl_{}".format(xbar["name"], esc_name) if module_key not in external_names: log.error("Inter-module key {} cannot be found in module, " "memory, top, or external lists.".format(module_key)) continue if port_iname is not None and port_mem is not None: log.error('Cannot make connection for {!r}: the base of the name ' 'points to a memory but memories do not support ' 'interface names.'.format(port['name'])) is_host = port['type'] == 'host' # If the hit is a module, it originally came from reggen (via # merge.py's amend_ip() function). In this case, we should have a # BusInterfaces object as well as a list of InterSignal objects. # # If not, this is a memory that will just have a dictionary of inter # signals. if port_mod is not None: block = name_to_block[port_mod['type']] try: sig_name = block.bus_interfaces.find_port_name( is_host, port_iname) except KeyError: log.error( 'Cannot make {} connection for {!r}: the base of ' 'the target module has no matching bus interface.'.format( 'host' if is_host else 'device', port['name'])) continue else: inter_signal_list = port_mem['inter_signal_list'] act = 'req' if is_host else 'rsp' matches = [ x for x in inter_signal_list if (x.get('package') == 'tlul_pkg' and x['struct'] == 'tl' and x['act'] == act) ] if not matches: log.error('Cannot make {} connection for {!r}: the memory ' 'has no signal with an action of {}.'.format( 'host' if is_host else 'device', port['name'], act)) continue assert len(matches) == 1 sig_name = matches[0]['name'] if is_host: add_intermodule_connection(obj=topcfg, req_m=xbar["name"], req_s="tl_" + esc_name, rsp_m=port_base, rsp_s=sig_name) else: add_intermodule_connection(obj=topcfg, req_m=port_base, req_s=sig_name, rsp_m=xbar["name"], rsp_s="tl_" + esc_name)
def autoconnect_xbar(topcfg: OrderedDict, xbar: OrderedDict): ports = [x for x in xbar["nodes"] if x["type"] in ["host", "device"]] for port in ports: if port["xbar"]: if port["type"] == "host": # Skip as device will add connection continue # Device port adds signal add_intermodule_connection(obj=topcfg, req_m=xbar["name"], req_s="tl_%s" % port["name"], rsp_m=port["name"], rsp_s="tl_%s" % xbar["name"]) continue # xbar port case # check if name exists in ["module", "memory"] ips = [ x for x in topcfg["module"] + topcfg["memory"] if x["name"] == port["name"] and lib.is_inst(x) ] assert len(ips) <= 1 if len(ips) == 0: # if not in module, memory, should be existed in top or ext field module_key = "{}.tl_{}".format(xbar["name"], port["name"]) if module_key not in topcfg["inter_module"]["top"] + list( topcfg["inter_module"]["external"].keys()): log.error("Inter-module key {} cannot be found in module, " "memory, top, or external lists.".format(module_key)) continue ip = ips[0] # Depending on whether ip came from reggen or topgen, it might be an # InterSignal object or it might be a dict. Extract the fields we need # so that the code below can treat it as a dict. isl = ip['inter_signal_list'] if not isl or isinstance(isl[0], InterSignal): inter_signal_list = [signal.as_dict() for signal in isl] else: inter_signal_list = isl # get the port name def get_signame(act: str) -> OrderedDict: ims = [ x for x in inter_signal_list if (x.get('package') == 'tlul_pkg' and x['struct'] == 'tl' and x['act'] == act) ] return ims if port["type"] == "device": ims = get_signame("rsp") else: # host type ims = get_signame("req") assert len(ims) == 1 sig_name = ims[0]["name"] add_intermodule_connection(obj=topcfg, req_m=port["name"], req_s=sig_name, rsp_m=xbar["name"], rsp_s="tl_%s" % port["name"]) continue # len() == 1