| # 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 | 
 | import re | 
 | from collections import OrderedDict | 
 | from enum import Enum | 
 | from typing import Dict, Tuple | 
 |  | 
 | from reggen.validate import check_int | 
 | from topgen import lib | 
 |  | 
 | IM_TYPES = ['uni', 'req_rsp'] | 
 | IM_ACTS = ['req', 'rsp', 'rcv'] | 
 | IM_VALID_TYPEACT = {'uni': ['req', 'rcv'], 'req_rsp': ['req', 'rsp']} | 
 | IM_CONN_TYPE = ['1-to-1', '1-to-N', 'broadcast'] | 
 |  | 
 |  | 
 | class ImType(Enum): | 
 |     Uni = 1 | 
 |     ReqRsp = 2 | 
 |  | 
 |  | 
 | class ImAct(Enum): | 
 |     Req = 1 | 
 |     Rsp = 2 | 
 |     Rcv = 3 | 
 |  | 
 |  | 
 | class ImConn(Enum): | 
 |     OneToOne = 1  # req <-> {rsp,rcv} with same width | 
 |     OneToN = 2  # req width N <-> N x {rsp,rcv}s width 1 | 
 |     Broadcast = 3  # req width 1 <-> N x rcvs width 1 | 
 |  | 
 |  | 
 | def intersignal_format(req: Dict) -> str: | 
 |     """Determine the signal format of the inter-module connections | 
 |  | 
 |     @param[req] Request struct. It has instance name, package format | 
 |                 and etc. | 
 |     """ | 
 |  | 
 |     # TODO: Handle array signal | 
 |     result = "{req}_{struct}".format(req=req["inst_name"], struct=req["name"]) | 
 |  | 
 |     # check signal length if exceeds 100 | 
 |  | 
 |     # 7 : space + . | 
 |     # 3 : _{i|o}( | 
 |     # 6 : _{req|rsp}), | 
 |     req_length = 7 + len(req["name"]) + 3 + len(result) + 6 | 
 |  | 
 |     if req_length > 100: | 
 |         logmsg = "signal {0} length cannot be greater than 100" | 
 |         log.warning(logmsg.format(result)) | 
 |         log.warning("Please consider shorten the instance name") | 
 |     return result | 
 |  | 
 |  | 
 | def elab_intermodule(topcfg: OrderedDict): | 
 |     """Check the connection of inter-module and categorize them | 
 |  | 
 |     In the top template, it uses updated inter_module fields to create | 
 |     connections between the modules (incl. memories). This function is to | 
 |     create and check the validity of the connections `inter_module` using IPs' | 
 |     `inter_signal_list`. | 
 |     """ | 
 |  | 
 |     list_of_intersignals = [] | 
 |  | 
 |     if "inter_signal" not in topcfg: | 
 |         topcfg["inter_signal"] = OrderedDict() | 
 |  | 
 |     # Gather the inter_signal_list | 
 |     instances = topcfg["module"] + topcfg["memory"] | 
 |  | 
 |     intermodule_instances = [x for x in instances if "inter_signal_list" in x] | 
 |  | 
 |     for x in intermodule_instances: | 
 |         for sig in x["inter_signal_list"]: | 
 |             # Add instance name to the entry and add to list_of_intersignals | 
 |             sig["inst_name"] = x["name"] | 
 |             list_of_intersignals.append(sig) | 
 |  | 
 |     # Add field to the topcfg | 
 |     topcfg["inter_signal"]["signals"] = list_of_intersignals | 
 |  | 
 |     # TODO: Cross check Can be done here not in validate as ipobj is not | 
 |     # available in validate | 
 |     error = check_intermodule(topcfg, "Inter-module Check") | 
 |     assert error == 0, "Inter-module validation is failed cannot move forward." | 
 |  | 
 |     # intermodule | 
 |     definitions = [] | 
 |  | 
 |     # Check the originator | 
 |     # As inter-module connection allow only 1:1, 1:N, or N:1, pick the most | 
 |     # common signals. If a requester connects to multiple responders/receivers, | 
 |     # the requester is main connector so that the definition becomes array. | 
 |     # | 
 |     # For example: | 
 |     #  inter_module: { | 
 |     #    'connect': { | 
 |     #      'pwr_mgr.pwrup': ['lc.pwrup', 'otp.pwrup'] | 
 |     #    } | 
 |     #  } | 
 |     # The tool adds `struct [1:0] pwr_mgr_pwrup` | 
 |     # It doesn't matter whether `pwr_mgr.pwrup` is requester or responder. | 
 |     # If the key is responder type, then the connection is made in reverse, | 
 |     # such that `lc.pwrup --> pwr_mgr.pwrup[0]` and | 
 |     # `otp.pwrup --> pwr_mgr.pwrup[1]` | 
 |  | 
 |     uid = 0  # Unique connection ID across the top | 
 |  | 
 |     for req, rsps in topcfg["inter_module"]["connect"].items(): | 
 |         log.info("{req} --> {rsps}".format(req=req, rsps=rsps)) | 
 |  | 
 |         # Split index | 
 |         req_module, req_signal, req_index = filter_index(req) | 
 |  | 
 |         # get the module signal | 
 |         req_struct = find_intermodule_signal(list_of_intersignals, req_module, | 
 |                                              req_signal) | 
 |  | 
 |         rsp_len = len(rsps) | 
 |         # decide signal format based on the `key` | 
 |         sig_name = intersignal_format(req_struct) | 
 |         req_struct["top_signame"] = sig_name | 
 |  | 
 |         # Find package in req, rsps | 
 |         if "package" in req_struct: | 
 |             package = req_struct["package"] | 
 |         else: | 
 |             for rsp in rsps: | 
 |                 rsp_module, rsp_signal, rsp_index = filter_index(rsp) | 
 |                 rsp_struct = find_intermodule_signal(list_of_intersignals, | 
 |                                                      rsp_module, rsp_signal) | 
 |                 if "package" in rsp_struct: | 
 |                     package = rsp_struct["package"] | 
 |                     break | 
 |             if not package: | 
 |                 package = "" | 
 |  | 
 |         # Add to definition | 
 |         if req_struct["type"] == "req_rsp": | 
 |             # Add two definitions | 
 |             definitions.append( | 
 |                 OrderedDict([('package', package), | 
 |                              ('struct', req_struct["struct"] + "_req"), | 
 |                              ('signame', sig_name + "_req"), | 
 |                              ('width', req_struct["width"]), | 
 |                              ('type', req_struct["type"])])) | 
 |             definitions.append( | 
 |                 OrderedDict([('package', package), | 
 |                              ('struct', req_struct["struct"] + "_rsp"), | 
 |                              ('signame', sig_name + "_rsp"), | 
 |                              ('width', req_struct["width"]), | 
 |                              ('type', req_struct["type"])])) | 
 |         else: | 
 |             # unidirection | 
 |             definitions.append( | 
 |                 OrderedDict([('package', package), | 
 |                              ('struct', req_struct["struct"]), | 
 |                              ('signame', sig_name), | 
 |                              ('width', req_struct["width"]), | 
 |                              ('type', req_struct["type"])])) | 
 |  | 
 |         req_struct["index"] = -1 | 
 |  | 
 |         for i, rsp in enumerate(rsps): | 
 |             # Split index | 
 |             rsp_module, rsp_signal, rsp_index = filter_index(rsp) | 
 |  | 
 |             rsp_struct = find_intermodule_signal(list_of_intersignals, | 
 |                                                  rsp_module, rsp_signal) | 
 |  | 
 |             # determine the signal name | 
 |  | 
 |             rsp_struct["top_signame"] = sig_name | 
 |             if req_struct["type"] == "uni" and req_struct[ | 
 |                     "top_type"] == "broadcast": | 
 |                 rsp_struct["index"] = -1 | 
 |             elif rsp_struct["width"] == req_struct["width"] and len(rsps) == 1: | 
 |                 rsp_struct["index"] = -1 | 
 |             else: | 
 |                 rsp_struct["index"] = -1 if req_struct["width"] == 1 else i | 
 |  | 
 |             # Assume it is logic | 
 |             # req_rsp doesn't allow logic | 
 |             if req_struct["struct"] == "logic": | 
 |                 assert req_struct[ | 
 |                     "type"] != "req_rsp", "logic signal cannot have req_rsp type" | 
 |  | 
 |             if rsp_len != 1: | 
 |                 log.warning("{req}[{i}] -> {rsp}".format(req=req, i=i, | 
 |                                                          rsp=rsp)) | 
 |             else: | 
 |                 log.warning("{req} -> {rsp}".format(req=req, rsp=rsp)) | 
 |  | 
 |             # increase Unique ID | 
 |             uid += 1 | 
 |  | 
 |     # TODO: Check unconnected port | 
 |     if "top" not in topcfg["inter_module"]: | 
 |         topcfg["inter_module"]["top"] = [] | 
 |  | 
 |     for s in topcfg["inter_module"]["top"]: | 
 |         sig_m, sig_s, sig_i = filter_index(s) | 
 |         assert sig_i is -1, 'top net connection should not use bit index' | 
 |         sig = find_intermodule_signal(list_of_intersignals, sig_m, sig_s) | 
 |         sig_name = intersignal_format(sig) | 
 |         sig["top_signame"] = sig_name | 
 |         if "index" not in sig: | 
 |             sig["index"] = -1 | 
 |  | 
 |         if sig["type"] == "req_rsp": | 
 |             # Add two definitions | 
 |             definitions.append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"] + "_req"), | 
 |                              ('signame', sig_name + "_req"), | 
 |                              ('width', sig["width"]), ('type', sig["type"])])) | 
 |             definitions.append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"] + "_rsp"), | 
 |                              ('signame', sig_name + "_rsp"), | 
 |                              ('width', sig["width"]), ('type', sig["type"])])) | 
 |         else:  # if sig["type"] == "uni": | 
 |             definitions.append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"]), ('signame', sig_name), | 
 |                              ('width', sig["width"]), ('type', sig["type"])])) | 
 |  | 
 |     if "external" not in topcfg["inter_module"]: | 
 |         topcfg["inter_module"]["external"] = [] | 
 |         topcfg["inter_signal"]["external"] = [] | 
 |  | 
 |     if "external" not in topcfg["inter_signal"]: | 
 |         topcfg["inter_signal"]["external"] = [] | 
 |  | 
 |     for s in topcfg["inter_module"]["external"]: | 
 |         sig_m, sig_s, sig_i = filter_index(s) | 
 |         assert sig_i is -1, 'top net connection should not use bit index' | 
 |         sig = find_intermodule_signal(list_of_intersignals, sig_m, sig_s) | 
 |         sig_name = intersignal_format(sig) | 
 |         sig["top_signame"] = sig_name | 
 |         if "index" not in sig: | 
 |             sig["index"] = -1 | 
 |  | 
 |         # Add the port definition to top external ports | 
 |         # TODO: Handle the suffix `_i`, `_o` correctly. | 
 |         # For now, external doesn't create _i, _o | 
 |         if sig["type"] == "req_rsp": | 
 |             topcfg["inter_signal"]["external"].append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"] + "_req"), | 
 |                              ('signame', sig_name + "_req"), | 
 |                              ('width', sig["width"]), ('type', sig["type"]), | 
 |                              ('direction', | 
 |                               'out' if sig['act'] == "req" else 'in')])) | 
 |             topcfg["inter_signal"]["external"].append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"] + "_rsp"), | 
 |                              ('signame', sig_name + "_rsp"), | 
 |                              ('width', sig["width"]), ('type', sig["type"]), | 
 |                              ('direction', | 
 |                               'in' if sig['act'] == "req" else 'out')])) | 
 |         else:  # uni | 
 |             topcfg["inter_signal"]["external"].append( | 
 |                 OrderedDict([('package', sig["package"]), | 
 |                              ('struct', sig["struct"]), ('signame', sig_name), | 
 |                              ('width', sig["width"]), ('type', sig["type"]), | 
 |                              ('direction', | 
 |                               'out' if sig['act'] == "req" else 'in')])) | 
 |  | 
 |     for sig in topcfg["inter_signal"]["signals"]: | 
 |         # Check if it exist in definitions | 
 |         if "top_signame" in sig: | 
 |             continue | 
 |  | 
 |         # Set index to -1 | 
 |         sig["index"] = -1 | 
 |  | 
 |         # TODO: Handle the unconnected port rule | 
 |  | 
 |     if "definitions" not in topcfg["inter_signal"]: | 
 |         topcfg["inter_signal"]["definitions"] = definitions | 
 |  | 
 |  | 
 | def filter_index(signame: str) -> Tuple[str, str, int]: | 
 |     """If the signal has array indicator `[N]` then split and return name and | 
 |     array index. If not, array index is -1. | 
 |  | 
 |     param signame module.sig{[N]} | 
 |  | 
 |     result (module_name, signal_name, array_index) | 
 |     """ | 
 |     m = re.match(r'(\w+)\.(\w+)(\[(\d+)\])*', signame) | 
 |  | 
 |     if not m: | 
 |         # Cannot match the pattern | 
 |         return "", "", -1 | 
 |  | 
 |     if m.group(3): | 
 |         # array index is not None | 
 |         return m.group(1), m.group(2), m.group(4) | 
 |  | 
 |     return m.group(1), m.group(2), -1 | 
 |  | 
 |  | 
 | def find_intermodule_signal(sig_list, m_name, s_name) -> Dict: | 
 |     """Return the intermodule signal structure | 
 |     """ | 
 |  | 
 |     filtered = [ | 
 |         x for x in sig_list if x["name"] == s_name and x["inst_name"] == m_name | 
 |     ] | 
 |  | 
 |     return filtered[0] if len(filtered) == 1 else None | 
 |  | 
 |  | 
 | # Validation | 
 | def check_intermodule_field(obj: OrderedDict, prefix: str = "") -> int: | 
 |     error = 0 | 
 |  | 
 |     # type check | 
 |     if obj["type"] not in IM_TYPES: | 
 |         log.error("{prefix} Inter_signal {name} " | 
 |                   "type {type} is incorrect.".format(prefix=prefix, | 
 |                                                      name=obj["name"], | 
 |                                                      type=obj["type"])) | 
 |         error += 1 | 
 |  | 
 |     if obj["act"] not in IM_ACTS: | 
 |         log.error("{prefix} Inter_signal {name} " | 
 |                   "act {act} is incorrect.".format(prefix=prefix, | 
 |                                                    name=obj["name"], | 
 |                                                    act=obj["act"])) | 
 |         error += 1 | 
 |  | 
 |     # Check if type and act are matched | 
 |     if error == 0: | 
 |         if obj["act"] not in IM_VALID_TYPEACT[obj['type']]: | 
 |             log.error("{type} and {act} of {name} are not a valid pair." | 
 |                       "".format(type=obj['type'], | 
 |                                 act=obj['act'], | 
 |                                 name=obj['name'])) | 
 |             error += 1 | 
 |     # Check 'width' field | 
 |     width = 1 | 
 |     if "width" not in obj: | 
 |         obj["width"] = 1 | 
 |     elif not isinstance(obj["width"], int): | 
 |         width, err = check_int(obj["width"], obj["name"]) | 
 |         if err: | 
 |             log.error("{prefix} Inter-module {inst}.{sig} 'width' " | 
 |                       "should be int type.".format(prefix=prefix, | 
 |                                                    inst=obj["inst_name"], | 
 |                                                    sig=obj["name"])) | 
 |             error += 1 | 
 |         else: | 
 |             # convert to int value | 
 |             obj["width"] = width | 
 |  | 
 |     return error | 
 |  | 
 |  | 
 | def check_intermodule(topcfg: Dict, prefix: str) -> int: | 
 |     if "inter_module" not in topcfg: | 
 |         return 0 | 
 |  | 
 |     total_error = 0 | 
 |  | 
 |     for req, rsps in topcfg["inter_module"]["connect"].items(): | 
 |         error = 0 | 
 |         # checking the key, value are in correct format | 
 |         # Allowed format | 
 |         #   1. module.signal | 
 |         #   2. module.signal[index] // Remember array is not yet supported | 
 |         #                           // But allow in format checker | 
 |         # | 
 |         # Example: | 
 |         #   inter_module: { | 
 |         #     'connect': { | 
 |         #       'flash_ctrl.flash': ['eflash.flash_ctrl'], | 
 |         #       'life_cycle.provision': ['debug_tap.dbg_en', 'dft_ctrl.en'], | 
 |         #       'otp.pwr_hold': ['pwrmgr.peri[0]'], | 
 |         #       'flash_ctrl.pwr_hold': ['pwrmgr.peri[1]'], | 
 |         #     } | 
 |         #   } | 
 |         # | 
 |         # If length of value list is > 1, then key should be array (width need to match) | 
 |         # If key is format #2, then lenght of value list shall be 1 | 
 |         # If one of the value is format #2, then the key should be 1 bit width and | 
 |         # entries of value list should be 1 | 
 |         req_m, req_s, req_i = filter_index(req) | 
 |  | 
 |         if req_s == "": | 
 |             log.error( | 
 |                 "Cannot parse the inter-module signal key '{req}'".format( | 
 |                     req=req)) | 
 |             error += 1 | 
 |  | 
 |         # Check rsps signal format is list | 
 |         if not isinstance(rsps, list): | 
 |             log.error("Value of key '{req}' should be a list".format(req=req)) | 
 |             error += 1 | 
 |             continue | 
 |  | 
 |         req_struct = find_intermodule_signal(topcfg["inter_signal"]["signals"], | 
 |                                              req_m, req_s) | 
 |  | 
 |         error += check_intermodule_field(req_struct) | 
 |  | 
 |         if req_i != -1 and len(rsps) != 1: | 
 |             # Array format should have one entry | 
 |             log.error( | 
 |                 "If key {req} has index, only one entry is allowed.".format( | 
 |                     req=req)) | 
 |             error += 1 | 
 |  | 
 |         total_width = 0 | 
 |         widths = [] | 
 |  | 
 |         # Check rsp format | 
 |         for i, rsp in enumerate(rsps): | 
 |             rsp_m, rsp_s, rsp_i = filter_index(rsp) | 
 |             if rsp_s == "": | 
 |                 log.error( | 
 |                     "Cannot parse the inter-module signal key '{req}->{rsp}'". | 
 |                     format(req=req, rsp=rsp)) | 
 |                 error += 1 | 
 |  | 
 |             rsp_struct = find_intermodule_signal( | 
 |                 topcfg["inter_signal"]["signals"], rsp_m, rsp_s) | 
 |  | 
 |             error += check_intermodule_field(rsp_struct) | 
 |  | 
 |             total_width += rsp_struct["width"] | 
 |             widths.append(rsp_struct["width"]) | 
 |  | 
 |             # Type check | 
 |             if "package" not in rsp_struct: | 
 |                 rsp_struct["package"] = req_struct["package"] | 
 |             elif req_struct["package"] != rsp_struct["package"]: | 
 |                 log.error( | 
 |                     "Inter-module package should be matched: " | 
 |                     "{req}->{rsp} exp({expected}), actual({actual})".format( | 
 |                         req=req_struct["name"], | 
 |                         rsp=rsp_struct["name"], | 
 |                         expected=req_struct["package"], | 
 |                         actual=rsp_struct["package"])) | 
 |                 error += 1 | 
 |             if req_struct["type"] != rsp_struct["type"]: | 
 |                 log.error( | 
 |                     "Inter-module type should be matched: " | 
 |                     "{req}->{rsp} exp({expected}), actual({actual})".format( | 
 |                         req=req_struct["name"], | 
 |                         rsp=rsp_struct["name"], | 
 |                         expected=req_struct["type"], | 
 |                         actual=rsp_struct["type"])) | 
 |                 error += 1 | 
 |  | 
 |             # If len(rsps) is 1, then the width should be matched to req | 
 |             if req_struct["width"] != 1: | 
 |                 if rsp_struct["width"] not in [1, req_struct["width"]]: | 
 |                     log.error( | 
 |                         "If req {req} is an array, " | 
 |                         "rsp {rsp} shall be non-array or array with same width" | 
 |                         .format(req=req, rsp=rsp)) | 
 |                     error += 1 | 
 |  | 
 |                 elif rsp_i != -1: | 
 |                     # If rsp has index, req should be width 1 | 
 |                     log.error( | 
 |                         "If rsp {rsp} has an array index, only one-to-one map is allowed." | 
 |                         .format(rsp=rsp)) | 
 |                     error += 1 | 
 |  | 
 |         # Determine if "uni" is broadcast or one-to-N | 
 |         if req_struct["type"] == "uni" and len(rsps) != 1: | 
 |             # If req width is same as total width of rsps ==> one-to-N | 
 |             if req_struct["width"] == total_width: | 
 |                 req_struct["top_type"] = "one-to-N" | 
 |  | 
 |             # If req width is same to the every width of rsps ==> broadcast | 
 |             elif len(rsps) * [req_struct["width"]] == widths: | 
 |                 req_struct["top_type"] = "broadcast" | 
 |  | 
 |             # If not, error | 
 |             else: | 
 |                 log.error("'uni' type connection {req} should be either" | 
 |                           "OneToN or Broadcast".format(req=req)) | 
 |                 error += 1 | 
 |         elif req_struct["type"] == "uni": | 
 |             # one-to-one connection | 
 |             req_struct["top_type"] = "broadcast" | 
 |  | 
 |         # If req is array, it is not allowed to have partial connections. | 
 |         # Doing for loop again here: Make code separate from other checker | 
 |         # for easier maintenance | 
 |         total_error += error | 
 |  | 
 |         if error != 0: | 
 |             # Skip the check | 
 |             continue | 
 |         rsps_width = 0 | 
 |         for rsp in rsps: | 
 |             rsp_m, rsp_s, rsp_i = filter_index(rsp) | 
 |             rsp_struct = find_intermodule_signal( | 
 |                 topcfg["inter_signal"]["signals"], rsp_m, rsp_s) | 
 |             # Update total responses width | 
 |             rsps_width += rsp_struct["width"] | 
 |  | 
 |         if req_struct["width"] != rsps_width: | 
 |             log.error( | 
 |                 "Request {} width is not matched with total responses width {}" | 
 |                 .format(req_struct["width"], rsps_width)) | 
 |             error += 1 | 
 |  | 
 |     for item in topcfg["inter_module"]["top"] + topcfg["inter_module"][ | 
 |             "external"]: | 
 |         sig_m, sig_s, sig_i = filter_index(item) | 
 |         if sig_i != -1: | 
 |             log.error("{item} cannot have index".format(item=item)) | 
 |             total_error += 1 | 
 |         sig_struct = find_intermodule_signal(topcfg["inter_signal"]["signals"], | 
 |                                              sig_m, sig_s) | 
 |         total_error += check_intermodule_field(sig_struct) | 
 |  | 
 |     return total_error | 
 |  | 
 |  | 
 | # Template functions | 
 | def im_defname(obj: OrderedDict) -> str: | 
 |     """return definition struct name | 
 |  | 
 |     e.g. flash_ctrl::flash_req_t | 
 |     """ | 
 |     if obj["package"] == "": | 
 |         # should be logic | 
 |         return "logic" | 
 |  | 
 |     return "{package}::{struct}_t".format(package=obj["package"], | 
 |                                           struct=obj["struct"]) | 
 |  | 
 |  | 
 | def im_netname(obj: OrderedDict, suffix: str = "") -> str: | 
 |     """return top signal name with index | 
 |     """ | 
 |  | 
 |     # Floating signals | 
 |     # TODO: Check logic type too | 
 |     # TODO: Find smarter way to assign default? | 
 |     if "top_signame" not in obj: | 
 |         if obj["act"] == "req" and suffix == "req": | 
 |             return "" | 
 |         if obj["act"] == "rsp" and suffix == "rsp": | 
 |             return "" | 
 |         if obj["act"] == "req" and suffix == "rsp": | 
 |             return "{package}::{struct}_RSP_DEFAULT".format( | 
 |                 package=obj["package"], struct=obj["struct"].upper()) | 
 |         if obj["act"] == "rsp" and suffix == "req": | 
 |             return "{package}::{struct}_REQ_DEFAULT".format( | 
 |                 package=obj["package"], struct=obj["struct"].upper()) | 
 |         if obj["act"] == "rcv" and suffix == "" and obj["struct"] == "logic": | 
 |             return "1'b0" | 
 |         if obj["act"] == "rcv" and suffix == "": | 
 |             return "{package}::{struct}_DEFAULT".format( | 
 |                 package=obj["package"], struct=obj["struct"].upper()) | 
 |  | 
 |         return "" | 
 |  | 
 |     # Connected signals | 
 |     assert suffix in ["", "req", "rsp"] | 
 |  | 
 |     suffix_s = "_{suffix}".format(suffix=suffix) if suffix != "" else suffix | 
 |     return "{top_signame}{suffix}{index}".format( | 
 |         top_signame=obj["top_signame"], | 
 |         suffix=suffix_s, | 
 |         index=lib.index(obj["index"])) | 
 |  | 
 |  | 
 | def im_portname(obj: OrderedDict, suffix: str = "") -> str: | 
 |     """return IP's port name | 
 |  | 
 |     e.g signame_o for requester req signal | 
 |     """ | 
 |     if suffix == "": | 
 |         suffix_s = "_o" if obj["act"] == "req" else "_i" | 
 |     elif suffix == "req": | 
 |         suffix_s = "_o" if obj["act"] == "req" else "_i" | 
 |     else: | 
 |         suffix_s = "_o" if obj["act"] == "rsp" else "_i" | 
 |  | 
 |     return "{signame}{suffix}".format(signame=obj["name"], suffix=suffix_s) |