SimObject.py (11802:be62996c95d1) | SimObject.py (11988:665cd5f8b52b) |
---|---|
1# Copyright (c) 2012 ARM Limited | 1# Copyright (c) 2017 ARM Limited |
2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated --- 26 unchanged lines hidden (view full) --- 36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40# 41# Authors: Steve Reinhardt 42# Nathan Binkert 43# Andreas Hansson | 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated --- 26 unchanged lines hidden (view full) --- 36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40# 41# Authors: Steve Reinhardt 42# Nathan Binkert 43# Andreas Hansson |
44# Andreas Sandberg |
|
44 45import sys 46from types import FunctionType, MethodType, ModuleType | 45 46import sys 47from types import FunctionType, MethodType, ModuleType |
48from functools import wraps 49import inspect |
|
47 48import m5 49from m5.util import * | 50 51import m5 52from m5.util import * |
53from m5.util.pybind import * |
|
50 51# Have to import params up top since Param is referenced on initial 52# load (when SimObject class references Param to create a class 53# variable, the 'name' param)... 54from m5.params import * 55# There are a few things we need that aren't in params.__all__ since 56# normal users don't need them 57from m5.params import ParamDesc, VectorParamDesc, \ --- 205 unchanged lines hidden (view full) --- 263 code() 264 code('void ${member_prefix}setName(const std::string &name_)' 265 '${end_of_decl}') 266 267 if not is_header: 268 code('{') 269 code.indent() 270 code('this->name = name_;') | 54 55# Have to import params up top since Param is referenced on initial 56# load (when SimObject class references Param to create a class 57# variable, the 'name' param)... 58from m5.params import * 59# There are a few things we need that aren't in params.__all__ since 60# normal users don't need them 61from m5.params import ParamDesc, VectorParamDesc, \ --- 205 unchanged lines hidden (view full) --- 267 code() 268 code('void ${member_prefix}setName(const std::string &name_)' 269 '${end_of_decl}') 270 271 if not is_header: 272 code('{') 273 code.indent() 274 code('this->name = name_;') |
271 code('this->pyobj = NULL;') | |
272 code.dedent() 273 code('}') 274 275 if is_header: 276 code('const std::string &${member_prefix}getName()') 277 code('{ return this->name; }') 278 279 code() --- 108 unchanged lines hidden (view full) --- 388 code('};') 389 390# The metaclass for SimObject. This class controls how new classes 391# that derive from SimObject are instantiated, and provides inherited 392# class behavior (just like a class controls how instances of that 393# class are instantiated, and provides inherited instance behavior). 394class MetaSimObject(type): 395 # Attributes that can be set only at initialization time | 275 code.dedent() 276 code('}') 277 278 if is_header: 279 code('const std::string &${member_prefix}getName()') 280 code('{ return this->name; }') 281 282 code() --- 108 unchanged lines hidden (view full) --- 391 code('};') 392 393# The metaclass for SimObject. This class controls how new classes 394# that derive from SimObject are instantiated, and provides inherited 395# class behavior (just like a class controls how instances of that 396# class are instantiated, and provides inherited instance behavior). 397class MetaSimObject(type): 398 # Attributes that can be set only at initialization time |
396 init_keywords = { 'abstract' : bool, 397 'cxx_class' : str, 398 'cxx_type' : str, 399 'cxx_header' : str, 400 'type' : str, 401 'cxx_bases' : list } | 399 init_keywords = { 400 'abstract' : bool, 401 'cxx_class' : str, 402 'cxx_type' : str, 403 'cxx_header' : str, 404 'type' : str, 405 'cxx_bases' : list, 406 'cxx_exports' : list, 407 'cxx_param_exports' : list, 408 } |
402 # Attributes that can be set any time 403 keywords = { 'check' : FunctionType } 404 405 # __new__ is called before __init__, and is where the statements 406 # in the body of the class definition get loaded into the class's 407 # __dict__. We intercept this to filter out parameter & port assignments 408 # and only allow "private" attributes to be passed to the base 409 # __new__ (starting with underscore). 410 def __new__(mcls, name, bases, dict): 411 assert name not in allClasses, "SimObject %s already present" % name 412 413 # Copy "private" attributes, functions, and classes to the 414 # official dict. Everything else goes in _init_dict to be 415 # filtered in __init__. 416 cls_dict = {} 417 value_dict = {} | 409 # Attributes that can be set any time 410 keywords = { 'check' : FunctionType } 411 412 # __new__ is called before __init__, and is where the statements 413 # in the body of the class definition get loaded into the class's 414 # __dict__. We intercept this to filter out parameter & port assignments 415 # and only allow "private" attributes to be passed to the base 416 # __new__ (starting with underscore). 417 def __new__(mcls, name, bases, dict): 418 assert name not in allClasses, "SimObject %s already present" % name 419 420 # Copy "private" attributes, functions, and classes to the 421 # official dict. Everything else goes in _init_dict to be 422 # filtered in __init__. 423 cls_dict = {} 424 value_dict = {} |
425 cxx_exports = [] |
|
418 for key,val in dict.items(): | 426 for key,val in dict.items(): |
427 try: 428 cxx_exports.append(getattr(val, "__pybind")) 429 except AttributeError: 430 pass 431 |
|
419 if public_value(key, val): 420 cls_dict[key] = val 421 else: 422 # must be a param/port setting 423 value_dict[key] = val 424 if 'abstract' not in value_dict: 425 value_dict['abstract'] = False 426 if 'cxx_bases' not in value_dict: 427 value_dict['cxx_bases'] = [] | 432 if public_value(key, val): 433 cls_dict[key] = val 434 else: 435 # must be a param/port setting 436 value_dict[key] = val 437 if 'abstract' not in value_dict: 438 value_dict['abstract'] = False 439 if 'cxx_bases' not in value_dict: 440 value_dict['cxx_bases'] = [] |
441 if 'cxx_exports' not in value_dict: 442 value_dict['cxx_exports'] = cxx_exports 443 else: 444 value_dict['cxx_exports'] += cxx_exports 445 if 'cxx_param_exports' not in value_dict: 446 value_dict['cxx_param_exports'] = [] |
|
428 cls_dict['_value_dict'] = value_dict 429 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 430 if 'type' in value_dict: 431 allClasses[name] = cls 432 return cls 433 434 # subclass initialization 435 def __init__(cls, name, bases, dict): --- 213 unchanged lines hidden (view full) --- 649 650 def __str__(cls): 651 return cls.__name__ 652 653 # See ParamValue.cxx_predecls for description. 654 def cxx_predecls(cls, code): 655 code('#include "params/$cls.hh"') 656 | 447 cls_dict['_value_dict'] = value_dict 448 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 449 if 'type' in value_dict: 450 allClasses[name] = cls 451 return cls 452 453 # subclass initialization 454 def __init__(cls, name, bases, dict): --- 213 unchanged lines hidden (view full) --- 668 669 def __str__(cls): 670 return cls.__name__ 671 672 # See ParamValue.cxx_predecls for description. 673 def cxx_predecls(cls, code): 674 code('#include "params/$cls.hh"') 675 |
676 def pybind_predecls(cls, code): 677 code('#include "${{cls.cxx_header}}"') 678 |
|
657 # See ParamValue.swig_predecls for description. 658 def swig_predecls(cls, code): 659 code('%import "python/_m5/param_$cls.i"') 660 661 # Hook for exporting additional C++ methods to Python via SWIG. 662 # Default is none, override using @classmethod in class definition. 663 def export_methods(cls, code): 664 pass --- 85 unchanged lines hidden (view full) --- 750 code('};') 751 752 for ns in reversed(namespaces): 753 code('} // namespace $ns') 754 755 code() 756 code('%include "params/$cls.hh"') 757 | 679 # See ParamValue.swig_predecls for description. 680 def swig_predecls(cls, code): 681 code('%import "python/_m5/param_$cls.i"') 682 683 # Hook for exporting additional C++ methods to Python via SWIG. 684 # Default is none, override using @classmethod in class definition. 685 def export_methods(cls, code): 686 pass --- 85 unchanged lines hidden (view full) --- 772 code('};') 773 774 for ns in reversed(namespaces): 775 code('} // namespace $ns') 776 777 code() 778 code('%include "params/$cls.hh"') 779 |
780 def pybind_decl(cls, code): 781 class_path = cls.cxx_class.split('::') 782 namespaces, classname = class_path[:-1], class_path[-1] 783 py_class_name = '_COLONS_'.join(class_path) if namespaces else \ 784 classname; |
|
758 | 785 |
786 # The 'local' attribute restricts us to the params declared in 787 # the object itself, not including inherited params (which 788 # will also be inherited from the base class's param struct 789 # here). Sort the params based on their key 790 params = map(lambda (k, v): v, sorted(cls._params.local.items())) 791 ports = cls._ports.local 792 793 code('''#include "pybind11/pybind11.h" 794#include "pybind11/stl.h" 795 796#include "sim/sim_object.hh" 797#include "params/$cls.hh" 798#include "sim/init.hh" 799#include "${{cls.cxx_header}}" 800 801''') 802 803 for param in params: 804 param.pybind_predecls(code) 805 806 code('''namespace py = pybind11; 807 808static void 809module_init(py::module &m_internal) 810{ 811 py::module m = m_internal.def_submodule("param_${cls}"); 812''') 813 code.indent() 814 if cls._base: 815 code('py::class_<${cls}Params, ${{cls._base.type}}Params>(m, ' \ 816 '"${cls}Params")') 817 else: 818 code('py::class_<${cls}Params>(m, "${cls}Params")') 819 820 code.indent() 821 if not hasattr(cls, 'abstract') or not cls.abstract: 822 code('.def(py::init<>())') 823 code('.def("create", &${cls}Params::create)') 824 825 param_exports = cls.cxx_param_exports + [ 826 PyBindProperty(k) 827 for k, v in sorted(cls._params.local.items()) 828 ] + [ 829 PyBindProperty("port_%s_connection_count" % port.name) 830 for port in ports.itervalues() 831 ] 832 for exp in param_exports: 833 exp.export(code, "%sParams" % cls) 834 835 code(';') 836 code() 837 code.dedent() 838 839 bases = [ cls._base.cxx_class ] + cls.cxx_bases if cls._base else \ 840 cls.cxx_bases 841 if bases: 842 base_str = ", ".join(bases) 843 code('py::class_<${{cls.cxx_class}}, ${base_str}>(m, ' \ 844 '"${py_class_name}")') 845 else: 846 code('py::class_<${{cls.cxx_class}}>(m, "${py_class_name}")') 847 code.indent() 848 for exp in cls.cxx_exports: 849 exp.export(code, cls.cxx_class) 850 code(';') 851 code.dedent() 852 code() 853 code.dedent() 854 code('}') 855 code() 856 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");', 857 cls, cls._base.type if cls._base else "") 858 859 |
|
759 # Generate the C++ declaration (.hh file) for this SimObject's 760 # param struct. Called from src/SConscript. 761 def cxx_param_decl(cls, code): 762 # The 'local' attribute restricts us to the params declared in 763 # the object itself, not including inherited params (which 764 # will also be inherited from the base class's param struct 765 # here). Sort the params based on their key 766 params = map(lambda (k, v): v, sorted(cls._params.local.items())) --- 8 unchanged lines hidden (view full) --- 775 class_path = cls._value_dict['cxx_class'].split('::') 776 777 code('''\ 778#ifndef __PARAMS__${cls}__ 779#define __PARAMS__${cls}__ 780 781''') 782 | 860 # Generate the C++ declaration (.hh file) for this SimObject's 861 # param struct. Called from src/SConscript. 862 def cxx_param_decl(cls, code): 863 # The 'local' attribute restricts us to the params declared in 864 # the object itself, not including inherited params (which 865 # will also be inherited from the base class's param struct 866 # here). Sort the params based on their key 867 params = map(lambda (k, v): v, sorted(cls._params.local.items())) --- 8 unchanged lines hidden (view full) --- 876 class_path = cls._value_dict['cxx_class'].split('::') 877 878 code('''\ 879#ifndef __PARAMS__${cls}__ 880#define __PARAMS__${cls}__ 881 882''') 883 |
884 885 # The base SimObject has a couple of params that get 886 # automatically set from Python without being declared through 887 # the normal Param mechanism; we slip them in here (needed 888 # predecls now, actual declarations below) 889 if cls == SimObject: 890 code('''#include <string>''') 891 |
|
783 # A forward class declaration is sufficient since we are just 784 # declaring a pointer. 785 for ns in class_path[:-1]: 786 code('namespace $ns {') 787 code('class $0;', class_path[-1]) 788 for ns in reversed(class_path[:-1]): 789 code('} // namespace $ns') 790 code() 791 | 892 # A forward class declaration is sufficient since we are just 893 # declaring a pointer. 894 for ns in class_path[:-1]: 895 code('namespace $ns {') 896 code('class $0;', class_path[-1]) 897 for ns in reversed(class_path[:-1]): 898 code('} // namespace $ns') 899 code() 900 |
792 # The base SimObject has a couple of params that get 793 # automatically set from Python without being declared through 794 # the normal Param mechanism; we slip them in here (needed 795 # predecls now, actual declarations below) 796 if cls == SimObject: 797 code(''' 798#ifndef PY_VERSION 799struct PyObject; 800#endif 801 802#include <string> 803''') | |
804 for param in params: 805 param.cxx_predecls(code) 806 for port in ports.itervalues(): 807 port.cxx_predecls(code) 808 code() 809 810 if cls._base: 811 code('#include "params/${{cls._base.type}}.hh"') --- 15 unchanged lines hidden (view full) --- 827 828 code.indent() 829 if cls == SimObject: 830 code(''' 831 SimObjectParams() {} 832 virtual ~SimObjectParams() {} 833 834 std::string name; | 901 for param in params: 902 param.cxx_predecls(code) 903 for port in ports.itervalues(): 904 port.cxx_predecls(code) 905 code() 906 907 if cls._base: 908 code('#include "params/${{cls._base.type}}.hh"') --- 15 unchanged lines hidden (view full) --- 924 925 code.indent() 926 if cls == SimObject: 927 code(''' 928 SimObjectParams() {} 929 virtual ~SimObjectParams() {} 930 931 std::string name; |
835 PyObject *pyobj; | |
836 ''') | 932 ''') |
933 |
|
837 for param in params: 838 param.cxx_decl(code) 839 for port in ports.itervalues(): 840 port.cxx_decl(code) 841 842 code.dedent() 843 code('};') 844 --- 11 unchanged lines hidden (view full) --- 856# SimObject class definition to the MetaSimObject methods (in 857# particular _set_param, which gets called for parameters with default 858# values defined on the SimObject class itself). It will get 859# overridden by the permanent definition (which requires that 860# SimObject be defined) lower in this file. 861def isSimObjectOrVector(value): 862 return False 863 | 934 for param in params: 935 param.cxx_decl(code) 936 for port in ports.itervalues(): 937 port.cxx_decl(code) 938 939 code.dedent() 940 code('};') 941 --- 11 unchanged lines hidden (view full) --- 953# SimObject class definition to the MetaSimObject methods (in 954# particular _set_param, which gets called for parameters with default 955# values defined on the SimObject class itself). It will get 956# overridden by the permanent definition (which requires that 957# SimObject be defined) lower in this file. 958def isSimObjectOrVector(value): 959 return False 960 |
961def cxxMethod(*args, **kwargs): 962 """Decorator to export C++ functions to Python""" 963 964 def decorate(func): 965 name = func.func_name 966 override = kwargs.get("override", False) 967 cxx_name = kwargs.get("cxx_name", name) 968 969 args, varargs, keywords, defaults = inspect.getargspec(func) 970 if varargs or keywords: 971 raise ValueError("Wrapped methods must not contain variable " \ 972 "arguments") 973 974 # Create tuples of (argument, default) 975 if defaults: 976 args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults) 977 # Don't include self in the argument list to PyBind 978 args = args[1:] 979 980 981 @wraps(func) 982 def cxx_call(self, *args, **kwargs): 983 ccobj = self.getCCObject() 984 return getattr(ccobj, name)(*args, **kwargs) 985 986 @wraps(func) 987 def py_call(self, *args, **kwargs): 988 return self.func(*args, **kwargs) 989 990 f = py_call if override else cxx_call 991 f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args) 992 993 return f 994 995 if len(args) == 0: 996 return decorate 997 elif len(args) == 1 and len(kwargs) == 0: 998 return decorate(*args) 999 else: 1000 raise TypeError("One argument and no kwargs, or only kwargs expected") 1001 |
|
864# This class holds information about each simobject parameter 865# that should be displayed on the command line for use in the 866# configuration system. 867class ParamInfo(object): 868 def __init__(self, type, desc, type_str, example, default_val, access_str): 869 self.type = type 870 self.desc = desc 871 self.type_str = type_str --- 44 unchanged lines hidden (view full) --- 916 void memWriteback(); 917 void regStats(); 918 void resetStats(); 919 void regProbePoints(); 920 void regProbeListeners(); 921 void startup(); 922''') 923 | 1002# This class holds information about each simobject parameter 1003# that should be displayed on the command line for use in the 1004# configuration system. 1005class ParamInfo(object): 1006 def __init__(self, type, desc, type_str, example, default_val, access_str): 1007 self.type = type 1008 self.desc = desc 1009 self.type_str = type_str --- 44 unchanged lines hidden (view full) --- 1054 void memWriteback(); 1055 void regStats(); 1056 void resetStats(); 1057 void regProbePoints(); 1058 void regProbeListeners(); 1059 void startup(); 1060''') 1061 |
1062 cxx_exports = [ 1063 PyBindMethod("init"), 1064 PyBindMethod("initState"), 1065 PyBindMethod("memInvalidate"), 1066 PyBindMethod("memWriteback"), 1067 PyBindMethod("regStats"), 1068 PyBindMethod("resetStats"), 1069 PyBindMethod("regProbePoints"), 1070 PyBindMethod("regProbeListeners"), 1071 PyBindMethod("startup"), 1072 ] 1073 1074 cxx_param_exports = [ 1075 PyBindProperty("name"), 1076 ] 1077 1078 @cxxMethod 1079 def loadState(self, cp): 1080 """Load SimObject state from a checkpoint""" 1081 pass 1082 |
|
924 # Returns a dict of all the option strings that can be 925 # generated as command line options for this simobject instance 926 # by tracing all reachable params in the top level instance and 927 # any children it contains. 928 def enumerateParams(self, flags_dict = {}, 929 cmd_line_str = "", access_str = ""): 930 if hasattr(self, "_paramEnumed"): 931 print "Cycle detected enumerating params" --- 442 unchanged lines hidden (view full) --- 1374 return d 1375 1376 def getCCParams(self): 1377 if self._ccParams: 1378 return self._ccParams 1379 1380 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type) 1381 cc_params = cc_params_struct() | 1083 # Returns a dict of all the option strings that can be 1084 # generated as command line options for this simobject instance 1085 # by tracing all reachable params in the top level instance and 1086 # any children it contains. 1087 def enumerateParams(self, flags_dict = {}, 1088 cmd_line_str = "", access_str = ""): 1089 if hasattr(self, "_paramEnumed"): 1090 print "Cycle detected enumerating params" --- 442 unchanged lines hidden (view full) --- 1533 return d 1534 1535 def getCCParams(self): 1536 if self._ccParams: 1537 return self._ccParams 1538 1539 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type) 1540 cc_params = cc_params_struct() |
1382 cc_params.pyobj = self | |
1383 cc_params.name = str(self) 1384 1385 param_names = self._params.keys() 1386 param_names.sort() 1387 for param in param_names: 1388 value = self._values.get(param) 1389 if value is None: 1390 fatal("%s.%s without default or user set value", 1391 self.path(), param) 1392 1393 value = value.getValue() 1394 if isinstance(self._params[param], VectorParamDesc): 1395 assert isinstance(value, list) 1396 vec = getattr(cc_params, param) 1397 assert not len(vec) | 1541 cc_params.name = str(self) 1542 1543 param_names = self._params.keys() 1544 param_names.sort() 1545 for param in param_names: 1546 value = self._values.get(param) 1547 if value is None: 1548 fatal("%s.%s without default or user set value", 1549 self.path(), param) 1550 1551 value = value.getValue() 1552 if isinstance(self._params[param], VectorParamDesc): 1553 assert isinstance(value, list) 1554 vec = getattr(cc_params, param) 1555 assert not len(vec) |
1398 for v in value: 1399 vec.append(v) | 1556 setattr(cc_params, param, list(value)) |
1400 else: 1401 setattr(cc_params, param, value) 1402 1403 port_names = self._ports.keys() 1404 port_names.sort() 1405 for port_name in port_names: 1406 port = self._port_refs.get(port_name, None) 1407 if port != None: --- 104 unchanged lines hidden (view full) --- 1512 1513 allClasses = baseClasses.copy() 1514 instanceDict = baseInstances.copy() 1515 noCxxHeader = False 1516 1517# __all__ defines the list of symbols that get exported when 1518# 'from config import *' is invoked. Try to keep this reasonably 1519# short to avoid polluting other namespaces. | 1557 else: 1558 setattr(cc_params, param, value) 1559 1560 port_names = self._ports.keys() 1561 port_names.sort() 1562 for port_name in port_names: 1563 port = self._port_refs.get(port_name, None) 1564 if port != None: --- 104 unchanged lines hidden (view full) --- 1669 1670 allClasses = baseClasses.copy() 1671 instanceDict = baseInstances.copy() 1672 noCxxHeader = False 1673 1674# __all__ defines the list of symbols that get exported when 1675# 'from config import *' is invoked. Try to keep this reasonably 1676# short to avoid polluting other namespaces. |
1520__all__ = [ 'SimObject' ] | 1677__all__ = [ 1678 'SimObject', 1679 'cxxMethod', 1680 'PyBindMethod', 1681 'PyBindProperty', 1682] |