configs: Port CPUConfig to use the common object list

Factor out ObjectList functionality from CPUConfig.

Change-Id: I34ca55142e14559e584d38b6cca3aa5c20923521
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20589
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/configs/common/CpuConfig.py b/configs/common/CpuConfig.py
index 0228148..9a0fcd9 100644
--- a/configs/common/CpuConfig.py
+++ b/configs/common/CpuConfig.py
@@ -40,66 +40,6 @@
 
 from m5 import fatal
 import m5.objects
-import inspect
-import sys
-from textwrap import TextWrapper
-
-# Dictionary of mapping names of real CPU models to classes.
-_cpu_classes = {}
-
-
-def is_cpu_class(cls):
-    """Determine if a class is a CPU that can be instantiated"""
-
-    # We can't use the normal inspect.isclass because the ParamFactory
-    # and ProxyFactory classes have a tendency to confuse it.
-    try:
-        return issubclass(cls, m5.objects.BaseCPU) and \
-            not cls.abstract and \
-            not issubclass(cls, m5.objects.CheckerCPU)
-    except (TypeError, AttributeError):
-        return False
-
-def _cpu_subclass_tester(name):
-    cpu_class = getattr(m5.objects, name, None)
-
-    def tester(cls):
-        return cpu_class is not None and cls is not None and \
-            issubclass(cls, cpu_class)
-
-    return tester
-
-is_kvm_cpu = _cpu_subclass_tester("BaseKvmCPU")
-is_noncaching_cpu = _cpu_subclass_tester("NonCachingSimpleCPU")
-
-def get(name):
-    """Get a CPU class from a user provided class name or alias."""
-
-    try:
-        cpu_class = _cpu_classes[name]
-        return cpu_class
-    except KeyError:
-        print("%s is not a valid CPU model." % (name,))
-        sys.exit(1)
-
-def print_cpu_list():
-    """Print a list of available CPU classes including their aliases."""
-
-    print("Available CPU classes:")
-    doc_wrapper = TextWrapper(initial_indent="\t\t", subsequent_indent="\t\t")
-    for name, cls in _cpu_classes.items():
-        print("\t%s" % name)
-
-        # Try to extract the class documentation from the class help
-        # string.
-        doc = inspect.getdoc(cls)
-        if doc:
-            for line in doc_wrapper.wrap(doc):
-                print(line)
-
-def cpu_names():
-    """Return a list of valid CPU names."""
-    return list(_cpu_classes.keys())
 
 def config_etrace(cpu_cls, cpu_list, options):
     if issubclass(cpu_cls, m5.objects.DerivO3CPU):
@@ -124,22 +64,3 @@
     else:
         fatal("%s does not support data dependency tracing. Use a CPU model of"
               " type or inherited from DerivO3CPU.", cpu_cls)
-
-# Add all CPUs in the object hierarchy.
-for name, cls in inspect.getmembers(m5.objects, is_cpu_class):
-    _cpu_classes[name] = cls
-
-
-from m5.defines import buildEnv
-from importlib import import_module
-for package in [ "generic", buildEnv['TARGET_ISA']]:
-    try:
-        package = import_module(".cores." + package,
-                                package=__name__.rpartition('.')[0])
-    except ImportError:
-        # No timing models for this ISA
-        continue
-
-    for mod_name, module in inspect.getmembers(package, inspect.ismodule):
-        for name, cls in inspect.getmembers(module, is_cpu_class):
-            _cpu_classes[name] = cls
diff --git a/configs/common/ObjectList.py b/configs/common/ObjectList.py
index fec78dc..31f8c41 100644
--- a/configs/common/ObjectList.py
+++ b/configs/common/ObjectList.py
@@ -103,3 +103,48 @@
         # Dictionary that maps names of real models to classes
         self._sub_classes = {}
         self._add_objects()
+
+class CPUList(ObjectList):
+    def _is_obj_class(self, cls):
+        """Determine if a class is a CPU that can be instantiated"""
+
+        # We can't use the normal inspect.isclass because the ParamFactory
+        # and ProxyFactory classes have a tendency to confuse it.
+        try:
+            return super(CPUList, self)._is_obj_class(cls) and \
+                not issubclass(cls, m5.objects.CheckerCPU)
+        except (TypeError, AttributeError):
+            return False
+
+    def _add_objects(self):
+        super(CPUList, self)._add_objects()
+
+        from m5.defines import buildEnv
+        from importlib import import_module
+        for package in [ "generic", buildEnv['TARGET_ISA']]:
+            try:
+                package = import_module(".cores." + package,
+                                        package=__name__.rpartition('.')[0])
+            except ImportError:
+                # No timing models for this ISA
+                continue
+
+            for mod_name, module in \
+                inspect.getmembers(package, inspect.ismodule):
+                for name, cls in inspect.getmembers(module,
+                    self._is_obj_class):
+                    self._sub_classes[name] = cls
+
+cpu_list = CPUList(m5.objects.BaseCPU)
+
+def _subclass_tester(name):
+    sub_class = getattr(m5.objects, name, None)
+
+    def tester(cls):
+        return sub_class is not None and cls is not None and \
+            issubclass(cls, sub_class)
+
+    return tester
+
+is_kvm_cpu = _subclass_tester("BaseKvmCPU")
+is_noncaching_cpu = _subclass_tester("NonCachingSimpleCPU")
diff --git a/configs/common/Options.py b/configs/common/Options.py
index f6fa0d0..57ee562 100644
--- a/configs/common/Options.py
+++ b/configs/common/Options.py
@@ -46,14 +46,14 @@
 from m5.objects import *
 
 from .Benchmarks import *
-from . import CpuConfig
+from . import ObjectList
 from . import BPConfig
 from . import HWPConfig
 from . import MemConfig
 from . import PlatformConfig
 
 def _listCpuTypes(option, opt, value, parser):
-    CpuConfig.print_cpu_list()
+    ObjectList.cpu_list.print()
     sys.exit(0)
 
 def _listBPTypes(option, opt, value, parser):
@@ -163,7 +163,7 @@
                       action="callback", callback=_listCpuTypes,
                       help="List available CPU types")
     parser.add_option("--cpu-type", type="choice", default="AtomicSimpleCPU",
-                      choices=CpuConfig.cpu_names(),
+                      choices=ObjectList.cpu_list.get_names(),
                       help = "type of cpu to run with")
     parser.add_option("--list-bp-types",
                       action="callback", callback=_listBPTypes,
@@ -317,7 +317,8 @@
     parser.add_option("--work-cpus-checkpoint-count", action="store", type="int",
                       help="checkpoint and exit when active cpu count is reached")
     parser.add_option("--restore-with-cpu", action="store", type="choice",
-                      default="AtomicSimpleCPU", choices=CpuConfig.cpu_names(),
+                      default="AtomicSimpleCPU",
+                      choices=ObjectList.cpu_list.get_names(),
                       help = "cpu type for restoring from a checkpoint")
 
 
diff --git a/configs/common/Simulation.py b/configs/common/Simulation.py
index 56107c1..457caf9 100644
--- a/configs/common/Simulation.py
+++ b/configs/common/Simulation.py
@@ -46,7 +46,8 @@
 from os import getcwd
 from os.path import join as joinpath
 
-from . import CpuConfig
+from common import CpuConfig
+from . import ObjectList
 from . import BPConfig
 from . import MemConfig
 
@@ -59,7 +60,7 @@
 
 def getCPUClass(cpu_type):
     """Returns the required cpu class and the mode of operation."""
-    cls = CpuConfig.get(cpu_type)
+    cls = ObjectList.cpu_list.get(cpu_type)
     return cls, cls.memory_mode()
 
 def setCPUClass(options):
diff --git a/configs/example/arm/devices.py b/configs/example/arm/devices.py
index ff7a2a1..4d746ed 100644
--- a/configs/example/arm/devices.py
+++ b/configs/example/arm/devices.py
@@ -45,9 +45,9 @@
 from m5.objects import *
 m5.util.addToPath('../../')
 from common.Caches import *
-from common import CpuConfig
+from common import ObjectList
 
-have_kvm = "ArmV8KvmCPU" in CpuConfig.cpu_names()
+have_kvm = "ArmV8KvmCPU" in ObjectList.cpu_list.get_names()
 
 class L1I(L1_ICache):
     tag_latency = 1
@@ -169,7 +169,8 @@
 
 class AtomicCluster(CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock, cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("AtomicSimpleCPU"), None, None, None, None ]
+        cpu_config = [ ObjectList.cpu_list.get("AtomicSimpleCPU"), None,
+                       None, None, None ]
         super(AtomicCluster, self).__init__(system, num_cpus, cpu_clock,
                                             cpu_voltage, *cpu_config)
     def addL1(self):
@@ -177,7 +178,8 @@
 
 class KvmCluster(CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock, cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("ArmV8KvmCPU"), None, None, None, None ]
+        cpu_config = [ ObjectList.cpu_list.get("ArmV8KvmCPU"), None, None,
+            None, None ]
         super(KvmCluster, self).__init__(system, num_cpus, cpu_clock,
                                          cpu_voltage, *cpu_config)
     def addL1(self):
diff --git a/configs/example/arm/fs_bigLITTLE.py b/configs/example/arm/fs_bigLITTLE.py
index dcc2a5d..a1ad2ce 100644
--- a/configs/example/arm/fs_bigLITTLE.py
+++ b/configs/example/arm/fs_bigLITTLE.py
@@ -53,7 +53,7 @@
 m5.util.addToPath("../../")
 
 from common import SysPaths
-from common import CpuConfig
+from common import ObjectList
 from common import PlatformConfig
 from common.cores.arm import ex5_big, ex5_LITTLE
 
@@ -85,32 +85,33 @@
 class BigCluster(devices.CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock,
                  cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("O3_ARM_v7a_3"), devices.L1I, devices.L1D,
-                    devices.WalkCache, devices.L2 ]
+        cpu_config = [ ObjectList.cpu_list.get("O3_ARM_v7a_3"),
+            devices.L1I, devices.L1D, devices.WalkCache, devices.L2 ]
         super(BigCluster, self).__init__(system, num_cpus, cpu_clock,
                                          cpu_voltage, *cpu_config)
 
 class LittleCluster(devices.CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock,
                  cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("MinorCPU"), devices.L1I, devices.L1D,
-                       devices.WalkCache, devices.L2 ]
+        cpu_config = [ ObjectList.cpu_list.get("MinorCPU"), devices.L1I,
+            devices.L1D, devices.WalkCache, devices.L2 ]
         super(LittleCluster, self).__init__(system, num_cpus, cpu_clock,
                                          cpu_voltage, *cpu_config)
 
 class Ex5BigCluster(devices.CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock,
                  cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("ex5_big"), ex5_big.L1I, ex5_big.L1D,
-                    ex5_big.WalkCache, ex5_big.L2 ]
+        cpu_config = [ ObjectList.cpu_list.get("ex5_big"), ex5_big.L1I,
+            ex5_big.L1D, ex5_big.WalkCache, ex5_big.L2 ]
         super(Ex5BigCluster, self).__init__(system, num_cpus, cpu_clock,
                                          cpu_voltage, *cpu_config)
 
 class Ex5LittleCluster(devices.CpuCluster):
     def __init__(self, system, num_cpus, cpu_clock,
                  cpu_voltage="1.0V"):
-        cpu_config = [ CpuConfig.get("ex5_LITTLE"), ex5_LITTLE.L1I,
-                    ex5_LITTLE.L1D, ex5_LITTLE.WalkCache, ex5_LITTLE.L2 ]
+        cpu_config = [ ObjectList.cpu_list.get("ex5_LITTLE"),
+            ex5_LITTLE.L1I, ex5_LITTLE.L1D, ex5_LITTLE.WalkCache,
+            ex5_LITTLE.L2 ]
         super(Ex5LittleCluster, self).__init__(system, num_cpus, cpu_clock,
                                          cpu_voltage, *cpu_config)
 
diff --git a/configs/example/fs.py b/configs/example/fs.py
index 386421d..ee813ff 100644
--- a/configs/example/fs.py
+++ b/configs/example/fs.py
@@ -62,8 +62,9 @@
 from common.Benchmarks import *
 from common import Simulation
 from common import CacheConfig
-from common import MemConfig
 from common import CpuConfig
+from common import MemConfig
+from common import ObjectList
 from common import BPConfig
 from common.Caches import *
 from common import Options
@@ -144,7 +145,8 @@
     test_sys.cpu = [TestCPUClass(clk_domain=test_sys.cpu_clk_domain, cpu_id=i)
                     for i in range(np)]
 
-    if CpuConfig.is_kvm_cpu(TestCPUClass) or CpuConfig.is_kvm_cpu(FutureClass):
+    if ObjectList.is_kvm_cpu(TestCPUClass) or \
+        ObjectList.is_kvm_cpu(FutureClass):
         test_sys.kvm_vm = KvmVM()
 
     if options.ruby:
@@ -193,7 +195,7 @@
 
         # Sanity check
         if options.simpoint_profile:
-            if not CpuConfig.is_noncaching_cpu(TestCPUClass):
+            if not ObjectList.is_noncaching_cpu(TestCPUClass):
                 fatal("SimPoint generation should be done with atomic cpu")
             if np > 1:
                 fatal("SimPoint generation not supported with more than one CPUs")
@@ -278,7 +280,7 @@
         print("Error: a kernel must be provided to run in full system mode")
         sys.exit(1)
 
-    if CpuConfig.is_kvm_cpu(DriveCPUClass):
+    if ObjectList.is_kvm_cpu(DriveCPUClass):
         drive_sys.kvm_vm = KvmVM()
 
     drive_sys.iobridge = Bridge(delay='50ns',
diff --git a/configs/example/se.py b/configs/example/se.py
index f43206a..e1396bf 100644
--- a/configs/example/se.py
+++ b/configs/example/se.py
@@ -62,6 +62,7 @@
 from common import Simulation
 from common import CacheConfig
 from common import CpuConfig
+from common import ObjectList
 from common import BPConfig
 from common import MemConfig
 from common.FileSystemConfig import config_filesystem
@@ -206,7 +207,7 @@
 for cpu in system.cpu:
     cpu.clk_domain = system.cpu_clk_domain
 
-if CpuConfig.is_kvm_cpu(CPUClass) or CpuConfig.is_kvm_cpu(FutureClass):
+if ObjectList.is_kvm_cpu(CPUClass) or ObjectList.is_kvm_cpu(FutureClass):
     if buildEnv['TARGET_ISA'] == 'x86':
         system.kvm_vm = KvmVM()
         for process in multiprocesses:
@@ -217,7 +218,7 @@
 
 # Sanity check
 if options.simpoint_profile:
-    if not CpuConfig.is_noncaching_cpu(CPUClass):
+    if not ObjectList.is_noncaching_cpu(CPUClass):
         fatal("SimPoint/BPProbe should be done with an atomic cpu")
     if np > 1:
         fatal("SimPoint generation not supported with more than one CPUs")