SimObject.py (13764:1647bbdc9444) SimObject.py (13778:318f777400e9)
1# Copyright (c) 2017-2018 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

--- 401 unchanged lines hidden (view full) ---

410 'cxx_class' : str,
411 'cxx_type' : str,
412 'cxx_header' : str,
413 'type' : str,
414 'cxx_base' : (str, type(None)),
415 'cxx_extra_bases' : list,
416 'cxx_exports' : list,
417 'cxx_param_exports' : list,
1# Copyright (c) 2017-2018 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

--- 401 unchanged lines hidden (view full) ---

410 'cxx_class' : str,
411 'cxx_type' : str,
412 'cxx_header' : str,
413 'type' : str,
414 'cxx_base' : (str, type(None)),
415 'cxx_extra_bases' : list,
416 'cxx_exports' : list,
417 'cxx_param_exports' : list,
418 'cxx_template_params' : list,
418 }
419 # Attributes that can be set any time
420 keywords = { 'check' : FunctionType }
421
422 # __new__ is called before __init__, and is where the statements
423 # in the body of the class definition get loaded into the class's
424 # __dict__. We intercept this to filter out parameter & port assignments
425 # and only allow "private" attributes to be passed to the base

--- 23 unchanged lines hidden (view full) ---

449 if 'cxx_extra_bases' not in value_dict:
450 value_dict['cxx_extra_bases'] = []
451 if 'cxx_exports' not in value_dict:
452 value_dict['cxx_exports'] = cxx_exports
453 else:
454 value_dict['cxx_exports'] += cxx_exports
455 if 'cxx_param_exports' not in value_dict:
456 value_dict['cxx_param_exports'] = []
419 }
420 # Attributes that can be set any time
421 keywords = { 'check' : FunctionType }
422
423 # __new__ is called before __init__, and is where the statements
424 # in the body of the class definition get loaded into the class's
425 # __dict__. We intercept this to filter out parameter & port assignments
426 # and only allow "private" attributes to be passed to the base

--- 23 unchanged lines hidden (view full) ---

450 if 'cxx_extra_bases' not in value_dict:
451 value_dict['cxx_extra_bases'] = []
452 if 'cxx_exports' not in value_dict:
453 value_dict['cxx_exports'] = cxx_exports
454 else:
455 value_dict['cxx_exports'] += cxx_exports
456 if 'cxx_param_exports' not in value_dict:
457 value_dict['cxx_param_exports'] = []
458 if 'cxx_template_params' not in value_dict:
459 value_dict['cxx_template_params'] = []
457 cls_dict['_value_dict'] = value_dict
458 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
459 if 'type' in value_dict:
460 allClasses[name] = cls
461 return cls
462
463 # subclass initialization
464 def __init__(cls, name, bases, dict):

--- 303 unchanged lines hidden (view full) ---

768 code.dedent()
769 code()
770 code.dedent()
771 code('}')
772 code()
773 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
774 cls, cls._base.type if cls._base else "")
775
460 cls_dict['_value_dict'] = value_dict
461 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
462 if 'type' in value_dict:
463 allClasses[name] = cls
464 return cls
465
466 # subclass initialization
467 def __init__(cls, name, bases, dict):

--- 303 unchanged lines hidden (view full) ---

771 code.dedent()
772 code()
773 code.dedent()
774 code('}')
775 code()
776 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
777 cls, cls._base.type if cls._base else "")
778
779 _warned_about_nested_templates = False
776
777 # Generate the C++ declaration (.hh file) for this SimObject's
778 # param struct. Called from src/SConscript.
779 def cxx_param_decl(cls, code):
780 # The 'local' attribute restricts us to the params declared in
781 # the object itself, not including inherited params (which
782 # will also be inherited from the base class's param struct
783 # here). Sort the params based on their key
784 params = map(lambda k_v: k_v[1], sorted(cls._params.local.items()))
785 ports = cls._ports.local
786 try:
787 ptypes = [p.ptype for p in params]
788 except:
789 print(cls, p, p.ptype_str)
790 print(params)
791 raise
792
780
781 # Generate the C++ declaration (.hh file) for this SimObject's
782 # param struct. Called from src/SConscript.
783 def cxx_param_decl(cls, code):
784 # The 'local' attribute restricts us to the params declared in
785 # the object itself, not including inherited params (which
786 # will also be inherited from the base class's param struct
787 # here). Sort the params based on their key
788 params = map(lambda k_v: k_v[1], sorted(cls._params.local.items()))
789 ports = cls._ports.local
790 try:
791 ptypes = [p.ptype for p in params]
792 except:
793 print(cls, p, p.ptype_str)
794 print(params)
795 raise
796
793 class_path = cls._value_dict['cxx_class'].split('::')
797 class CxxClass(object):
798 def __init__(self, sig, template_params=[]):
799 # Split the signature into its constituent parts. This could
800 # potentially be done with regular expressions, but
801 # it's simple enough to pick appart a class signature
802 # manually.
803 parts = sig.split('<', 1)
804 base = parts[0]
805 t_args = []
806 if len(parts) > 1:
807 # The signature had template arguments.
808 text = parts[1].rstrip(' \t\n>')
809 arg = ''
810 # Keep track of nesting to avoid splitting on ","s embedded
811 # in the arguments themselves.
812 depth = 0
813 for c in text:
814 if c == '<':
815 depth = depth + 1
816 if depth > 0 and not \
817 self._warned_about_nested_templates:
818 self._warned_about_nested_templates = True
819 print('Nested template argument in cxx_class.'
820 ' This feature is largely untested and '
821 ' may not work.')
822 elif c == '>':
823 depth = depth - 1
824 elif c == ',' and depth == 0:
825 t_args.append(arg.strip())
826 arg = ''
827 else:
828 arg = arg + c
829 if arg:
830 t_args.append(arg.strip())
831 # Split the non-template part on :: boundaries.
832 class_path = base.split('::')
794
833
834 # The namespaces are everything except the last part of the
835 # class path.
836 self.namespaces = class_path[:-1]
837 # And the class name is the last part.
838 self.name = class_path[-1]
839
840 self.template_params = template_params
841 self.template_arguments = []
842 # Iterate through the template arguments and their values. This
843 # will likely break if parameter packs are used.
844 for arg, param in zip(t_args, template_params):
845 type_keys = ('class', 'typename')
846 # If a parameter is a type, parse it recursively. Otherwise
847 # assume it's a constant, and store it verbatim.
848 if any(param.strip().startswith(kw) for kw in type_keys):
849 self.template_arguments.append(CxxClass(arg))
850 else:
851 self.template_arguments.append(arg)
852
853 def declare(self, code):
854 # First declare any template argument types.
855 for arg in self.template_arguments:
856 if isinstance(arg, CxxClass):
857 arg.declare(code)
858 # Re-open the target namespace.
859 for ns in self.namespaces:
860 code('namespace $ns {')
861 # If this is a class template...
862 if self.template_params:
863 code('template <${{", ".join(self.template_params)}}>')
864 # The actual class declaration.
865 code('class ${{self.name}};')
866 # Close the target namespaces.
867 for ns in reversed(self.namespaces):
868 code('} // namespace $ns')
869
795 code('''\
796#ifndef __PARAMS__${cls}__
797#define __PARAMS__${cls}__
798
799''')
800
801
802 # The base SimObject has a couple of params that get
803 # automatically set from Python without being declared through
804 # the normal Param mechanism; we slip them in here (needed
805 # predecls now, actual declarations below)
806 if cls == SimObject:
807 code('''#include <string>''')
808
870 code('''\
871#ifndef __PARAMS__${cls}__
872#define __PARAMS__${cls}__
873
874''')
875
876
877 # The base SimObject has a couple of params that get
878 # automatically set from Python without being declared through
879 # the normal Param mechanism; we slip them in here (needed
880 # predecls now, actual declarations below)
881 if cls == SimObject:
882 code('''#include <string>''')
883
884 cxx_class = CxxClass(cls._value_dict['cxx_class'],
885 cls._value_dict['cxx_template_params'])
886
809 # A forward class declaration is sufficient since we are just
810 # declaring a pointer.
887 # A forward class declaration is sufficient since we are just
888 # declaring a pointer.
811 for ns in class_path[:-1]:
812 code('namespace $ns {')
813 code('class $0;', class_path[-1])
814 for ns in reversed(class_path[:-1]):
815 code('} // namespace $ns')
816 code()
889 cxx_class.declare(code)
817
818 for param in params:
819 param.cxx_predecls(code)
820 for port in ports.values():
821 port.cxx_predecls(code)
822 code()
823
824 if cls._base:

--- 857 unchanged lines hidden ---
890
891 for param in params:
892 param.cxx_predecls(code)
893 for port in ports.values():
894 port.cxx_predecls(code)
895 code()
896
897 if cls._base:

--- 857 unchanged lines hidden ---