Exemplo n.º 1
0
    def _get_class_name(self, node: Node) -> str:
        """
        Returns the class type name.
        Shall be unique enough to prevent type name collisions
        """
        if self.reuse_class_definitions:
            scope_path = self._get_resolved_scope_path(node, "__")

            if scope_path is not None:
                class_name = scope_path
            else:
                # Unable to determine a reusable type name. Fall back to hierarchical path
                class_name = node.get_rel_path(
                    self.top.parent,
                    hier_separator="__", array_suffix="", empty_array_suffix=""
                )
                # Add prefix to prevent collision when mixing namespace methods
                class_name = "xtern__" + class_name
        else:
            class_name = node.get_rel_path(
                self.top.parent,
                hier_separator="__", array_suffix="", empty_array_suffix=""
            )

        return class_name
Exemplo n.º 2
0
def get_node_uid(node: Node) -> str:
    """
    Returns the node's UID string
    """
    node_path = node.get_path(array_suffix="", empty_array_suffix="")
    path_hash = hashlib.sha1(node_path.encode('utf-8')).hexdigest()
    return path_hash
Exemplo n.º 3
0
    def _get_class_friendly_name(self, node: Node) -> str:
        """
        Returns a useful string that helps identify the class definition in
        a comment
        """
        if self.reuse_class_definitions:
            scope_path = self._get_resolved_scope_path(node)

            if scope_path is not None:
                friendly_name = scope_path
            else:
                # Unable to determine a reusable type name. Fall back to hierarchical path
                friendly_name = node.get_rel_path(self.top.parent)
        else:
            friendly_name = node.get_rel_path(self.top.parent)

        return type(node.inst).__name__ + " - " + friendly_name
Exemplo n.º 4
0
 def has_extra_property_doc(self, node: Node) -> bool:
     """
     Returns True if node has a property set that is to be explicitly
     documented.
     """
     for prop in self.extra_properties:
         if prop in node.list_properties():
             return True
     return False
Exemplo n.º 5
0
    def _get_bus_width(self, node: Node) -> int:
        """
        Returns group-like node's bus width (in bytes)
        """
        width = self.bus_width_db[node.get_path()]

        # Divide by 8, rounded up
        if width % 8:
            return width // 8 + 1
        else:
            return width // 8
Exemplo n.º 6
0
    def check_udp(self, prop_name: str, node: Node) -> bool:
        """
        Checks if the property name is a udp
        """

        prop_ups = node.list_properties(include_native=False, include_udp=True)

        if prop_name in prop_ups:
            return True
        else:
            return False
Exemplo n.º 7
0
    def _get_class_name_new(self, node: Node) -> str:
        """
        Returns the class type name.
        Shall be unique enough to prevent type name collisions
        """
        if self.reuse_class_definitions:
            pass
        else:
            class_name = node.get_rel_path(
                self.top.parent,
                hier_separator="__", array_suffix="", empty_array_suffix=""
            )

        return class_name
Exemplo n.º 8
0
    def _get_class_friendly_name(self, node: Node) -> str:
        """
        Returns a useful string that helps identify the class definition in
        a comment
        """
        if self.reuse_class_definitions:
            scope_path = node.inst.get_scope_path()

            if (scope_path is not None) and (node.type_name is not None):
                if scope_path:
                    friendly_name = scope_path + "::" + node.type_name
                else:
                    friendly_name = node.type_name
            else:
                # Unable to determine a reusable type name. Fall back to hierarchical path
                friendly_name = node.get_rel_path(self.top.parent,
                                                  hier_separator="__",
                                                  array_suffix="",
                                                  empty_array_suffix="")
        else:
            friendly_name = node.get_rel_path(self.top.parent)

        return type(node.inst).__name__ + " - " + friendly_name
Exemplo n.º 9
0
    def _get_signal_name(self,
                         node: Node,
                         index: str = '',
                         prop: str = '') -> str:
        """
        Returns unique-in-addrmap name for signals
        """
        prefix = node.get_rel_path(node.owning_addrmap, '', '_', '', '')

        # check for override, otherwise use prop
        suffix = self.signal_overrides.get(prop, prop)

        if prop:
            return "{}_{}{}".format(prefix, suffix, index)
        else:
            return "{}{}".format(prefix, index)
Exemplo n.º 10
0
def has_description(node: Node) -> bool:
    """
    Test if node has a description defined
    """
    return "desc" in node.list_properties()
Exemplo n.º 11
0
    def get_node_html_desc(self,
                           node: Node,
                           increment_heading: int = 0) -> 'Optional[str]':
        """
        Wrapper function to get HTML description
        If no description, returns None

        Performs the following transformations on top of the built-in HTML desc
        output:
        - Increment any heading tags
        - Transform img paths that point to local files. Copy referenced image to output
        """

        desc = node.get_html_desc(self.markdown_inst)
        if desc is None:
            return desc

        # Keep HTML semantically correct by promoting heading tags if desc ends
        # up as a child of existing headings.
        if increment_heading > 0:

            def heading_replace_callback(m: 're.Match') -> str:
                new_heading = "<%sh%d>" % (
                    m.group(1), min(int(m.group(2)) + increment_heading, 6))
                return new_heading

            desc = re.sub(r'<(/?)[hH](\d)>', heading_replace_callback, desc)

        # Transform image references
        # If an img reference points to a file on the local filesystem, then
        # copy it to the output and transform the reference
        if increment_heading > 0:

            def img_transform_callback(m: 're.Match') -> str:
                dom = xml.dom.minidom.parseString(m.group(0))
                img_src = dom.childNodes[0].attributes["src"].value

                if os.path.isabs(img_src):
                    # Absolute local path, or root URL
                    pass
                elif re.match(r'(https?|file)://', img_src):
                    # Absolute URL
                    pass
                else:
                    # Looks like a relative path
                    # See if it points to something relative to the source file
                    path = self.try_resolve_rel_path(node.inst.def_src_ref,
                                                     img_src)
                    if path is not None:
                        img_src = path

                if os.path.exists(img_src):
                    with open(img_src, 'rb') as f:
                        md5 = hashlib.md5(f.read()).hexdigest()
                    new_path = os.path.join(
                        self.output_dir, "content",
                        "%s_%s" % (md5[0:8], os.path.basename(img_src)))
                    shutil.copyfile(img_src, new_path)
                    dom.childNodes[0].attributes["src"].value = os.path.join(
                        "content",
                        "%s_%s" % (md5[0:8], os.path.basename(img_src)))
                    return dom.childNodes[0].toxml()

                return m.group(0)

            desc = re.sub(r'<\s*img.*/>', img_transform_callback, desc)
        return desc
Exemplo n.º 12
0
    def visit_addressable_node(self,
                               node: Node,
                               parent_id: 'Optional[int]' = None) -> int:
        self.current_id += 1
        this_id = self.current_id
        child_ids = []  # type: List[int]

        ral_entry = {
            'parent': parent_id,
            'children': child_ids,
            'name': node.inst.inst_name,
            'offset': BigInt(node.inst.addr_offset),
            'size': BigInt(node.size),
        }
        if node.inst.is_array:
            ral_entry['dims'] = node.inst.array_dimensions
            ral_entry['stride'] = BigInt(node.inst.array_stride)
            ral_entry['idxs'] = [0] * len(node.inst.array_dimensions)

        if isinstance(node, RegNode):
            ral_fields = []
            for field in node.fields():
                field_reset = field.get_property("reset", default=0)
                if isinstance(field_reset, Node):
                    # Reset value is a reference. Dynamic RAL data does not
                    # support this, so stuff a 0 in its place
                    field_reset = 0

                ral_field = {
                    'name': field.inst.inst_name,
                    'lsb': field.inst.lsb,
                    'msb': field.inst.msb,
                    'reset': BigInt(field_reset),
                    'disp': 'H'
                }

                field_enum = field.get_property("encode")
                if field_enum is not None:
                    encode = OrderedDict()
                    for member in field_enum:
                        encode[member.name] = BigInt(member.value)
                    ral_field['encode'] = encode
                    ral_field['disp'] = 'E'

                ral_fields.append(ral_field)

            ral_entry['fields'] = ral_fields

        # Insert entry now to ensure proper position in list
        self.RALIndex.append(ral_entry)

        # Insert root nodes to list
        if parent_id is None:
            self.RootNodeIds.append(this_id)

        # Recurse to children
        children = OrderedDict()
        for child in node.children():
            if not isinstance(child, AddressableNode):
                continue
            child_id = self.visit_addressable_node(child, this_id)
            child_ids.append(child_id)
            children[child_id] = child

        # Generate page for this node
        self.write_page(this_id, node, children)

        return this_id
Exemplo n.º 13
0
    def export(self, node: Node, path: str, **kwargs):
        """
        Perform the export!

        Parameters
        ----------
        node: systemrdl.Node
            Top-level node to export. Can be the top-level `RootNode` or any
            internal `AddrmapNode`.
        path: str
            Output file.
        export_as_package: bool
            If True (Default), UVM register model is exported as a SystemVerilog
            package. Package name is based on the output file name.

            If False, register model is exported as an includable header.
        reuse_class_definitions: bool
            If True (Default), exporter attempts to re-use class definitions
            where possible. Class names are based on the lexical scope of the
            original SystemRDL definitions.

            If False, class definitions are not reused. Class names are based on
            the instance's hierarchical path.
        use_uvm_factory: bool
            If True, class definitions and class instances are created using the
            UVM factory.

            If False (Default), UVM factory is disabled. Classes are created
            directly via new() constructors.
        """
        export_as_package = kwargs.pop("export_as_package", True)
        use_uvm_factory = kwargs.pop("use_uvm_factory", False)
        self.reuse_class_definitions = kwargs.pop("reuse_class_definitions", True)

        # Check for stray kwargs
        if kwargs:
            raise TypeError("got an unexpected keyword argument '%s'" % list(kwargs.keys())[0])

        # If it is the root node, skip to top addrmap
        if isinstance(node, RootNode):
            node = node.top
        self.top = node

        if isinstance(node, AddrmapNode) and node.get_property('bridge'):
            node.env.msg.warning(
                "UVM RAL generator does not have proper support for bridge addmaps yet. The 'bridge' property will be ignored.",
                node.inst.property_src_ref.get('bridge', node.inst.inst_src_ref)
            )

        # First, traverse the model and collect some information
        self.bus_width_db = {}
        RDLWalker().walk(self.top, PreExportListener(self))

        context = {
            'top_node': node,
            'RegNode': RegNode,
            'RegfileNode': RegfileNode,
            'AddrmapNode': AddrmapNode,
            'MemNode': MemNode,
            'AddressableNode': AddressableNode,
            'isinstance': isinstance,
            'class_needs_definition': self._class_needs_definition,
            'get_class_name': self._get_class_name,
            'get_class_friendly_name': self._get_class_friendly_name,
            'get_inst_name': self._get_inst_name,
            'get_field_access': self._get_field_access,
            'get_array_address_offset_expr': self._get_array_address_offset_expr,
            'get_endianness': self._get_endianness,
            'get_bus_width': self._get_bus_width,
            'get_mem_access': self._get_mem_access,
            'roundup_to': self._roundup_to,
            'roundup_pow2': self._roundup_pow2,
            'use_uvm_factory': use_uvm_factory,
        }

        context.update(self.user_template_context)

        if export_as_package:
            context['package_name'] = self._get_package_name(path)
            template = self.jj_env.get_template("top_pkg.sv")
        else:
            context['include_guard'] = self._get_include_guard(path)
            template = self.jj_env.get_template("top_include.svh")
        stream = template.stream(context)
        stream.dump(path)
Exemplo n.º 14
0
    def export(self, node: Node, path: str, **kwargs):
        """
        Perform the export!

        Parameters
        ----------
        node: systemrdl.Node
            Top-level node to export. Can be the top-level `RootNode` or any
            internal `AddrmapNode`.
        path: str
            Output file.
        signal_overrides: dict
            Mapping to override default signal suffixes , e.g. {'incr' : 'increment'}
        bus_type: str
            bus type for the SW interface (default: native)
        """
        self.signal_overrides = kwargs.pop("signal_overrides") or dict()
        bus_type = kwargs.pop("bus_type", "native")

        try:
            with open(
                    os.path.join(os.path.dirname(__file__), "busses",
                                 "{}.ports.sv".format(bus_type))) as f:
                sw_ports = f.read()
            with open(
                    os.path.join(os.path.dirname(__file__), "busses",
                                 "{}.impl.sv".format(bus_type))) as f:
                sw_impl = f.read()
        except FileNotFoundError as e:
            raise TypeError(
                "didn't recognise bus_type '{}'. Please check for typos.".
                format(bus_type)) from e

        if type(self.signal_overrides) != dict:
            raise TypeError(
                "got an unexpected signal_overrides argument of type {} instead of dict"
                .format(type(self.signal_overrides)))

        # Check for stray kwargs
        if kwargs:
            raise TypeError("got an unexpected keyword argument '%s'" %
                            list(kwargs.keys())[0])

        # If it is the root node, skip to top addrmap
        if isinstance(node, RootNode):
            node = node.top

        # go through top level regfiles
        modules = []
        for desc in node.descendants():
            if ((isinstance(desc, (RegfileNode, RegNode)))
                    and isinstance(desc.parent, AddrmapNode)):
                if desc.parent not in modules:
                    modules.append(desc.parent)

        for block in modules:
            self.top = block

            # First, traverse the model and collect some information
            #self.bus_width_db = {}
            #RDLWalker().walk(self.top)

            context = {
                'print': print,
                'type': type,
                'top_node': block,
                'sw_ports': sw_ports,
                'sw_impl': sw_impl,
                'FieldNode': FieldNode,
                'RegNode': RegNode,
                'RegfileNode': RegfileNode,
                'AddrmapNode': AddrmapNode,
                'MemNode': MemNode,
                'AddressableNode': AddressableNode,
                'SignalNode': SignalNode,
                'OnWriteType': OnWriteType,
                'OnReadType': OnReadType,
                'InterruptType': InterruptType,
                'PropertyReference': PropertyReference,
                'isinstance': isinstance,
                'signal': self._get_signal_name,
                'full_idx': self._full_idx,
                'get_inst_name': self._get_inst_name,
                'get_prop_value': self._get_prop_value,
                'get_counter_value': self._get_counter_value,
            }

            context.update(self.user_template_context)

            # ensure directory exists
            Path(path).mkdir(parents=True, exist_ok=True)

            template = self.jj_env.get_template("module.sv")
            stream = template.stream(context)
            stream.dump(os.path.join(path, node.inst_name + '_rf.sv'))
            template = self.jj_env.get_template("tb.sv")
            stream = template.stream(context)
            stream.dump(os.path.join(path, node.inst_name + '_tb.sv'))
            template = self.jj_env.get_template("tb.cpp")
            stream = template.stream(context)
            stream.dump(os.path.join(path, node.inst_name + '_tb.cpp'))

        return [self._get_inst_name(m) for m in modules]
Exemplo n.º 15
0
 def get_desc(self, node: Node) -> str:
     s = (node.get_property("desc", default="")).replace("\n", " ")
     s = s.replace("  ", " ")
     return s
Exemplo n.º 16
0
 def get_name(self, node: Node) -> str:
     s = node.get_property("name")
     return s
Exemplo n.º 17
0
def stringify_component_ref(value: node.Node, owner_node: node.Node) -> str:
    return value.get_rel_path(owner_node)
Exemplo n.º 18
0
 def signal_prefix(self, node: Node) -> str:
     """
     Returns unique-in-addrmap prefix for signals
     """
     return node.get_rel_path(node.owning_addrmap, '', '_', '_', '')