# Copyright 2004-2006 The Regents of The University of Michigan # Copyright 2010-20013 Advanced Micro Devices, Inc. # Copyright 2013 Mark D. Hill and David A. Wood # Copyright 2017-2020 ARM Limited # Copyright 2021 Google, Inc. # # The license below extends only to copyright in the software and shall # not be construed as granting a license to any other intellectual # property including but not limited to intellectual property relating # to a hardware implementation of the functionality of the software # licensed hereunder. You may use the software subject to the license # terms below provided that you ensure that this notice is replicated # unmodified and in its entirety in all distributions of the software, # modified or unmodified, in source code or in binary form. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import argparse import importlib import os.path import sys import importer from code_formatter import code_formatter parser = argparse.ArgumentParser() parser.add_argument("modpath", help="module the simobject belongs to") parser.add_argument("param_hh", help="parameter header file to generate") args = parser.parse_args() basename = os.path.basename(args.param_hh) sim_object_name = os.path.splitext(basename)[0] importer.install() module = importlib.import_module(args.modpath) sim_object = getattr(module, sim_object_name) from m5.objects.SimObject import SimObject from m5.params import Enum code = code_formatter() # The 'local' attribute restricts us to the params declared in # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). Sort the params based on their key params = list( map(lambda k_v: k_v[1], sorted(sim_object._params.local.items())) ) ports = sim_object._ports.local try: ptypes = [p.ptype for p in params] except: print(sim_object) print(params) raise warned_about_nested_templates = False class CxxClass(object): def __init__(self, sig, template_params=[]): # Split the signature into its constituent parts. This could # potentially be done with regular expressions, but # it's simple enough to pick appart a class signature # manually. parts = sig.split("<", 1) base = parts[0] t_args = [] if len(parts) > 1: # The signature had template arguments. text = parts[1].rstrip(" \t\n>") arg = "" # Keep track of nesting to avoid splitting on ","s embedded # in the arguments themselves. depth = 0 for c in text: if c == "<": depth = depth + 1 if depth > 0 and not warned_about_nested_templates: warned_about_nested_templates = True print( "Nested template argument in cxx_class." " This feature is largely untested and " " may not work." ) elif c == ">": depth = depth - 1 elif c == "," and depth == 0: t_args.append(arg.strip()) arg = "" else: arg = arg + c if arg: t_args.append(arg.strip()) # Split the non-template part on :: boundaries. class_path = base.split("::") # The namespaces are everything except the last part of the class path. self.namespaces = class_path[:-1] # And the class name is the last part. self.name = class_path[-1] self.template_params = template_params self.template_arguments = [] # Iterate through the template arguments and their values. This # will likely break if parameter packs are used. for arg, param in zip(t_args, template_params): type_keys = ("class", "typename") # If a parameter is a type, parse it recursively. Otherwise # assume it's a constant, and store it verbatim. if any(param.strip().startswith(kw) for kw in type_keys): self.template_arguments.append(CxxClass(arg)) else: self.template_arguments.append(arg) def declare(self, code): # First declare any template argument types. for arg in self.template_arguments: if isinstance(arg, CxxClass): arg.declare(code) # Re-open the target namespace. for ns in self.namespaces: code("namespace $ns {") # If this is a class template... if self.template_params: code('template <${{", ".join(self.template_params)}}>') # The actual class declaration. code("class ${{self.name}};") # Close the target namespaces. for ns in reversed(self.namespaces): code("} // namespace $ns") code( """\ #ifndef __PARAMS__${sim_object}__ #define __PARAMS__${sim_object}__ """ ) # The base SimObject has a couple of params that get # automatically set from Python without being declared through # the normal Param mechanism; we slip them in here (needed # predecls now, actual declarations below) if sim_object == SimObject: code("""#include """) cxx_class = CxxClass( sim_object._value_dict["cxx_class"], sim_object._value_dict["cxx_template_params"], ) # A forward class declaration is sufficient since we are just # declaring a pointer. cxx_class.declare(code) for param in params: param.cxx_predecls(code) for port in ports.values(): port.cxx_predecls(code) code() if sim_object._base: code('#include "params/${{sim_object._base.type}}.hh"') code() for ptype in ptypes: if issubclass(ptype, Enum): code('#include "enums/${{ptype.__name__}}.hh"') code() code("namespace gem5") code("{") code("") # now generate the actual param struct code("struct ${sim_object}Params") if sim_object._base: code(" : public ${{sim_object._base.type}}Params") code("{") if not hasattr(sim_object, "abstract") or not sim_object.abstract: if "type" in sim_object.__dict__: code(" ${{sim_object.cxx_type}} create() const;") code.indent() if sim_object == SimObject: code( """ SimObjectParams() {} virtual ~SimObjectParams() {} std::string name; """ ) for param in params: param.cxx_decl(code) for port in ports.values(): port.cxx_decl(code) code.dedent() code("};") code() code("} // namespace gem5") code() code("#endif // __PARAMS__${sim_object}__") code.write(args.param_hh)