summaryrefslogtreecommitdiff
path: root/src/python/m5
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/m5')
-rw-r--r--src/python/m5/SimObject.py205
-rw-r--r--src/python/m5/__init__.py200
-rw-r--r--src/python/m5/environment.py43
-rw-r--r--src/python/m5/params.py229
-rw-r--r--src/python/m5/simulate.py199
-rw-r--r--src/python/m5/ticks.py6
6 files changed, 608 insertions, 274 deletions
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index f87e13732..1e7d289e2 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -29,6 +29,8 @@
import sys, types
+import proxy
+import m5
from util import *
from multidict import multidict
@@ -61,7 +63,7 @@ def isSimObjectOrSequence(value):
from params import *
# There are a few things we need that aren't in params.__all__ since
# normal users don't need them
-from params import ParamDesc, isNullPointer, SimObjVector
+from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector
noDot = False
try:
@@ -109,6 +111,9 @@ except:
#
#####################################################################
+# list of all SimObject classes
+allClasses = {}
+
# dict to look up SimObjects based on path
instanceDict = {}
@@ -119,12 +124,14 @@ instanceDict = {}
class MetaSimObject(type):
# Attributes that can be set only at initialization time
init_keywords = { 'abstract' : types.BooleanType,
+ 'cxx_namespace' : types.StringType,
+ 'cxx_class' : types.StringType,
+ 'cxx_type' : types.StringType,
+ 'cxx_predecls' : types.ListType,
+ 'swig_predecls' : types.ListType,
'type' : types.StringType }
# Attributes that can be set any time
- keywords = { 'check' : types.FunctionType,
- 'cxx_type' : types.StringType,
- 'cxx_predecls' : types.ListType,
- 'swig_predecls' : types.ListType }
+ keywords = { 'check' : types.FunctionType }
# __new__ is called before __init__, and is where the statements
# in the body of the class definition get loaded into the class's
@@ -132,6 +139,8 @@ class MetaSimObject(type):
# and only allow "private" attributes to be passed to the base
# __new__ (starting with underscore).
def __new__(mcls, name, bases, dict):
+ assert name not in allClasses
+
# Copy "private" attributes, functions, and classes to the
# official dict. Everything else goes in _init_dict to be
# filtered in __init__.
@@ -144,8 +153,13 @@ class MetaSimObject(type):
else:
# must be a param/port setting
value_dict[key] = val
+ if 'abstract' not in value_dict:
+ value_dict['abstract'] = False
cls_dict['_value_dict'] = value_dict
- return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
+ cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
+ if 'type' in value_dict:
+ allClasses[name] = cls
+ return cls
# subclass initialization
def __init__(cls, name, bases, dict):
@@ -183,6 +197,34 @@ class MetaSimObject(type):
# mark base as having been subclassed
base._instantiated = True
+ # default keyword values
+ if 'type' in cls._value_dict:
+ _type = cls._value_dict['type']
+ if 'cxx_class' not in cls._value_dict:
+ cls._value_dict['cxx_class'] = _type
+
+ namespace = cls._value_dict.get('cxx_namespace', None)
+
+ _cxx_class = cls._value_dict['cxx_class']
+ if 'cxx_type' not in cls._value_dict:
+ t = _cxx_class + '*'
+ if namespace:
+ t = '%s::%s' % (namespace, t)
+ cls._value_dict['cxx_type'] = t
+ if 'cxx_predecls' not in cls._value_dict:
+ # A forward class declaration is sufficient since we are
+ # just declaring a pointer.
+ decl = 'class %s;' % _cxx_class
+ if namespace:
+ decl = 'namespace %s { %s }' % (namespace, decl)
+ cls._value_dict['cxx_predecls'] = [decl]
+
+ if 'swig_predecls' not in cls._value_dict:
+ # A forward class declaration is sufficient since we are
+ # just declaring a pointer.
+ cls._value_dict['swig_predecls'] = \
+ cls._value_dict['cxx_predecls']
+
# Now process the _value_dict items. They could be defining
# new (or overriding existing) parameters or ports, setting
# class keywords (e.g., 'abstract'), or setting parameter
@@ -207,12 +249,6 @@ class MetaSimObject(type):
else:
setattr(cls, key, val)
- cls.cxx_type = cls.type + '*'
- # A forward class declaration is sufficient since we are just
- # declaring a pointer.
- cls.cxx_predecls = ['class %s;' % cls.type]
- cls.swig_predecls = cls.cxx_predecls
-
def _set_keyword(cls, keyword, val, kwtype):
if not isinstance(val, kwtype):
raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
@@ -310,18 +346,19 @@ class MetaSimObject(type):
return cls.__name__
def cxx_decl(cls):
- code = "#ifndef __PARAMS__%s\n#define __PARAMS__%s\n\n" % (cls, cls)
-
if str(cls) != 'SimObject':
base = cls.__bases__[0].type
else:
base = None
+ code = "#ifndef __PARAMS__%s\n" % cls
+ code += "#define __PARAMS__%s\n\n" % cls
+
# The 'dict' 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).
- params = cls._params.dict.values()
+ params = cls._params.local.values()
try:
ptypes = [p.ptype for p in params]
except:
@@ -330,9 +367,10 @@ class MetaSimObject(type):
raise
# get a list of lists of predeclaration lines
- predecls = [p.cxx_predecls() for p in params]
- # flatten
- predecls = reduce(lambda x,y:x+y, predecls, [])
+ predecls = []
+ predecls.extend(cls.cxx_predecls)
+ for p in params:
+ predecls.extend(p.cxx_predecls())
# remove redundant lines
predecls2 = []
for pd in predecls:
@@ -345,17 +383,21 @@ class MetaSimObject(type):
if base:
code += '#include "params/%s.hh"\n\n' % base
- # Generate declarations for locally defined enumerations.
- enum_ptypes = [t for t in ptypes if issubclass(t, Enum)]
- if enum_ptypes:
- code += "\n".join([t.cxx_decl() for t in enum_ptypes])
- code += "\n\n"
+ for ptype in ptypes:
+ if issubclass(ptype, Enum):
+ code += '#include "enums/%s.hh"\n' % ptype.__name__
+ code += "\n\n"
# now generate the actual param struct
code += "struct %sParams" % cls
if base:
code += " : public %sParams" % base
- code += " {\n"
+ code += "\n{\n"
+ if cls == SimObject:
+ code += " virtual ~%sParams() {}\n" % cls
+ if not hasattr(cls, 'abstract') or not cls.abstract:
+ if 'type' in cls.__dict__:
+ code += " %s create();\n" % cls.cxx_type
decls = [p.cxx_decl() for p in params]
decls.sort()
code += "".join([" %s\n" % d for d in decls])
@@ -365,12 +407,34 @@ class MetaSimObject(type):
code += "\n#endif\n"
return code
+ def cxx_type_decl(cls):
+ if str(cls) != 'SimObject':
+ base = cls.__bases__[0]
+ else:
+ base = None
+
+ code = ''
+
+ if base:
+ code += '#include "%s_type.h"\n' % base
+
+ # now generate dummy code for inheritance
+ code += "struct %s" % cls.cxx_class
+ if base:
+ code += " : public %s" % base.cxx_class
+ code += "\n{};\n"
+
+ return code
+
def swig_decl(cls):
+ code = '%%module %s\n' % cls
- code = '%%module %sParams\n' % cls
+ code += '%{\n'
+ code += '#include "params/%s.hh"\n' % cls
+ code += '%}\n\n'
if str(cls) != 'SimObject':
- base = cls.__bases__[0].type
+ base = cls.__bases__[0]
else:
base = None
@@ -378,11 +442,12 @@ class MetaSimObject(type):
# the object itself, not including inherited params (which
# will also be inherited from the base class's param struct
# here).
- params = cls._params.dict.values()
+ params = cls._params.local.values()
ptypes = [p.ptype for p in params]
# get a list of lists of predeclaration lines
- predecls = [p.swig_predecls() for p in params]
+ predecls = []
+ predecls.extend([ p.swig_predecls() for p in params ])
# flatten
predecls = reduce(lambda x,y:x+y, predecls, [])
# remove redundant lines
@@ -395,11 +460,14 @@ class MetaSimObject(type):
code += "\n\n";
if base:
- code += '%%import "python/m5/swig/%sParams.i"\n\n' % base
+ code += '%%import "params/%s.i"\n\n' % base
- code += '%{\n'
- code += '#include "params/%s.hh"\n' % cls
- code += '%}\n\n'
+ for ptype in ptypes:
+ if issubclass(ptype, Enum):
+ code += '%%import "enums/%s.hh"\n' % ptype.__name__
+ code += "\n\n"
+
+ code += '%%import "params/%s_type.hh"\n\n' % cls
code += '%%include "params/%s.hh"\n\n' % cls
return code
@@ -412,6 +480,7 @@ class SimObject(object):
# get this metaclass.
__metaclass__ = MetaSimObject
type = 'SimObject'
+ abstract = True
name = Param.String("Object name")
@@ -440,6 +509,7 @@ class SimObject(object):
self._parent = None
self._children = {}
self._ccObject = None # pointer to C++ object
+ self._ccParams = None
self._instantiated = False # really "cloned"
# Inherit parameter values from class using multidict so
@@ -577,8 +647,11 @@ class SimObject(object):
value._maybe_set_parent(self, attr)
elif isSimObjectSequence(value):
value = SimObjVector(value)
- [v._maybe_set_parent(self, "%s%d" % (attr, i))
- for i,v in enumerate(value)]
+ if len(value) == 1:
+ value[0]._maybe_set_parent(self, attr)
+ else:
+ for i,v in enumerate(value):
+ v._maybe_set_parent(self, "%s%d" % (attr, i))
self._values[attr] = value
@@ -680,25 +753,66 @@ class SimObject(object):
for child in child_names:
self._children[child].print_ini()
- # Call C++ to create C++ object corresponding to this object and
- # (recursively) all its children
- def createCCObject(self):
- self.getCCObject() # force creation
- for child in self._children.itervalues():
- child.createCCObject()
+ def getCCParams(self):
+ if self._ccParams:
+ return self._ccParams
+
+ cc_params_struct = eval('m5.objects.params.%sParams' % self.type)
+ cc_params = cc_params_struct()
+ cc_params.object = self
+ cc_params.name = str(self)
+
+ param_names = self._params.keys()
+ param_names.sort()
+ for param in param_names:
+ value = self._values.get(param)
+ if value is None:
+ continue
+
+ value = value.getValue()
+ if isinstance(self._params[param], VectorParamDesc):
+ assert isinstance(value, list)
+ vec = getattr(cc_params, param)
+ assert not len(vec)
+ for v in value:
+ vec.append(v)
+ else:
+ setattr(cc_params, param, value)
+
+ port_names = self._ports.keys()
+ port_names.sort()
+ for port_name in port_names:
+ port = self._port_refs.get(port_name, None)
+ if port != None:
+ setattr(cc_params, port_name, port)
+ self._ccParams = cc_params
+ return self._ccParams
# Get C++ object corresponding to this object, calling C++ if
# necessary to construct it. Does *not* recursively create
# children.
def getCCObject(self):
+ import internal
+ params = self.getCCParams()
if not self._ccObject:
self._ccObject = -1 # flag to catch cycles in recursion
- self._ccObject = internal.sim_object.createSimObject(self.path())
+ self._ccObject = params.create()
elif self._ccObject == -1:
raise RuntimeError, "%s: recursive call to getCCObject()" \
% self.path()
return self._ccObject
+ # Call C++ to create C++ object corresponding to this object and
+ # (recursively) all its children
+ def createCCObject(self):
+ self.getCCParams()
+ self.getCCObject() # force creation
+ for child in self._children.itervalues():
+ child.createCCObject()
+
+ def getValue(self):
+ return self.getCCObject()
+
# Create C++ port connections corresponding to the connections in
# _port_refs (& recursively for all children)
def connectPorts(self):
@@ -730,6 +844,7 @@ class SimObject(object):
return system_ptr.getMemoryMode()
def changeTiming(self, mode):
+ import internal
if isinstance(self, m5.objects.System):
# i don't know if there's a better way to do this - calling
# setMemoryMode directly from self._ccObject results in calling
@@ -740,6 +855,7 @@ class SimObject(object):
child.changeTiming(mode)
def takeOverFrom(self, old_cpu):
+ import internal
cpu_ptr = internal.sim_object.convertToBaseCPUPtr(old_cpu._ccObject)
self._ccObject.takeOverFrom(cpu_ptr)
@@ -794,9 +910,4 @@ def resolveSimObject(name):
# __all__ defines the list of symbols that get exported when
# 'from config import *' is invoked. Try to keep this reasonably
# short to avoid polluting other namespaces.
-__all__ = ['SimObject']
-
-# see comment on imports at end of __init__.py.
-import proxy
-import internal
-import m5
+__all__ = [ 'SimObject' ]
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
index a9206a474..36f2eba61 100644
--- a/src/python/m5/__init__.py
+++ b/src/python/m5/__init__.py
@@ -27,19 +27,10 @@
# Authors: Nathan Binkert
# Steve Reinhardt
-import atexit
import os
import sys
-# import the SWIG-wrapped main C++ functions
-import internal
-# import a few SWIG-wrapped items (those that are likely to be used
-# directly by user scripts) completely into this module for
-# convenience
-import event
-
-# import the m5 compile options
-import defines
+import smartdict
# define a MaxTick parameter
MaxTick = 2**63 - 1
@@ -69,178 +60,12 @@ def AddToPath(path):
sys.path.insert(1, path)
# make a SmartDict out of the build options for our local use
-import smartdict
build_env = smartdict.SmartDict()
-build_env.update(defines.m5_build_env)
# make a SmartDict out of the OS environment too
env = smartdict.SmartDict()
env.update(os.environ)
-# The final hook to generate .ini files. Called from the user script
-# once the config is built.
-def instantiate(root):
- # we need to fix the global frequency
- ticks.fixGlobalFrequency()
-
- root.unproxy_all()
- # ugly temporary hack to get output to config.ini
- sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w')
- root.print_ini()
- sys.stdout.close() # close config.ini
- sys.stdout = sys.__stdout__ # restore to original
-
- # load config.ini into C++
- internal.core.loadIniFile(resolveSimObject)
-
- # Initialize the global statistics
- internal.stats.initSimStats()
-
- # Create the C++ sim objects and connect ports
- root.createCCObject()
- root.connectPorts()
-
- # Do a second pass to finish initializing the sim objects
- internal.sim_object.initAll()
-
- # Do a third pass to initialize statistics
- internal.sim_object.regAllStats()
-
- # Check to make sure that the stats package is properly initialized
- internal.stats.check()
-
- # Reset to put the stats in a consistent state.
- internal.stats.reset()
-
-def doDot(root):
- dot = pydot.Dot()
- instance.outputDot(dot)
- dot.orientation = "portrait"
- dot.size = "8.5,11"
- dot.ranksep="equally"
- dot.rank="samerank"
- dot.write("config.dot")
- dot.write_ps("config.ps")
-
-need_resume = []
-need_startup = True
-def simulate(*args, **kwargs):
- global need_resume, need_startup
-
- if need_startup:
- internal.core.SimStartup()
- need_startup = False
-
- for root in need_resume:
- resume(root)
- need_resume = []
-
- return internal.event.simulate(*args, **kwargs)
-
-# Export curTick to user script.
-def curTick():
- return internal.core.cvar.curTick
-
-# Python exit handlers happen in reverse order. We want to dump stats last.
-atexit.register(internal.stats.dump)
-
-# register our C++ exit callback function with Python
-atexit.register(internal.core.doExitCleanup)
-
-# This loops until all objects have been fully drained.
-def doDrain(root):
- all_drained = drain(root)
- while (not all_drained):
- all_drained = drain(root)
-
-# Tries to drain all objects. Draining might not be completed unless
-# all objects return that they are drained on the first call. This is
-# because as objects drain they may cause other objects to no longer
-# be drained.
-def drain(root):
- all_drained = False
- drain_event = internal.event.createCountedDrain()
- unready_objects = root.startDrain(drain_event, True)
- # If we've got some objects that can't drain immediately, then simulate
- if unready_objects > 0:
- drain_event.setCount(unready_objects)
- simulate()
- else:
- all_drained = True
- internal.event.cleanupCountedDrain(drain_event)
- return all_drained
-
-def resume(root):
- root.resume()
-
-def checkpoint(root, dir):
- if not isinstance(root, objects.Root):
- raise TypeError, "Checkpoint must be called on a root object."
- doDrain(root)
- print "Writing checkpoint"
- internal.sim_object.serializeAll(dir)
- resume(root)
-
-def restoreCheckpoint(root, dir):
- print "Restoring from checkpoint"
- internal.sim_object.unserializeAll(dir)
- need_resume.append(root)
-
-def changeToAtomic(system):
- if not isinstance(system, (objects.Root, objects.System)):
- raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
- (type(system), objects.Root, objects.System)
- if system.getMemoryMode() != internal.sim_object.SimObject.Atomic:
- doDrain(system)
- print "Changing memory mode to atomic"
- system.changeTiming(internal.sim_object.SimObject.Atomic)
-
-def changeToTiming(system):
- if not isinstance(system, (objects.Root, objects.System)):
- raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
- (type(system), objects.Root, objects.System)
-
- if system.getMemoryMode() != internal.sim_object.SimObject.Timing:
- doDrain(system)
- print "Changing memory mode to timing"
- system.changeTiming(internal.sim_object.SimObject.Timing)
-
-def switchCpus(cpuList):
- print "switching cpus"
- if not isinstance(cpuList, list):
- raise RuntimeError, "Must pass a list to this function"
- for i in cpuList:
- if not isinstance(i, tuple):
- raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
-
- [old_cpus, new_cpus] = zip(*cpuList)
-
- for cpu in old_cpus:
- if not isinstance(cpu, objects.BaseCPU):
- raise TypeError, "%s is not of type BaseCPU" % cpu
- for cpu in new_cpus:
- if not isinstance(cpu, objects.BaseCPU):
- raise TypeError, "%s is not of type BaseCPU" % cpu
-
- # Drain all of the individual CPUs
- drain_event = internal.event.createCountedDrain()
- unready_cpus = 0
- for old_cpu in old_cpus:
- unready_cpus += old_cpu.startDrain(drain_event, False)
- # If we've got some objects that can't drain immediately, then simulate
- if unready_cpus > 0:
- drain_event.setCount(unready_cpus)
- simulate()
- internal.event.cleanupCountedDrain(drain_event)
- # Now all of the CPUs are ready to be switched out
- for old_cpu in old_cpus:
- old_cpu._ccObject.switchOut()
- index = 0
- for new_cpu in new_cpus:
- new_cpu.takeOverFrom(old_cpus[index])
- new_cpu._ccObject.resume()
- index += 1
-
# Since we have so many mutual imports in this package, we should:
# 1. Put all intra-package imports at the *bottom* of the file, unless
# they're absolutely needed before that (for top-level statements
@@ -250,7 +75,24 @@ def switchCpus(cpuList):
# you can get the wrong result if foo is only partially imported
# at the point you do that (i.e., because foo is in the middle of
# importing *you*).
-from main import options
-import objects
+try:
+ import internal
+ running_m5 = True
+except ImportError:
+ running_m5 = False
+
+if running_m5:
+ from event import *
+ from simulate import *
+ from main import options
+
+if running_m5:
+ import defines
+ build_env.update(defines.m5_build_env)
+else:
+ import __scons
+ build_env.update(__scons.m5_build_env)
+
+import SimObject
import params
-from SimObject import resolveSimObject
+import objects
diff --git a/src/python/m5/environment.py b/src/python/m5/environment.py
new file mode 100644
index 000000000..bea0bc1d0
--- /dev/null
+++ b/src/python/m5/environment.py
@@ -0,0 +1,43 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# 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.
+#
+# Authors: Nathan Binkert
+# Steve Reinhardt
+
+import os
+
+# import the m5 compile options
+import defines
+
+# make a SmartDict out of the build options for our local use
+import smartdict
+build_env = smartdict.SmartDict()
+build_env.update(defines.m5_build_env)
+
+# make a SmartDict out of the OS environment too
+env = smartdict.SmartDict()
+env.update(os.environ)
+
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index 88b162874..3fca4e97a 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -47,6 +47,7 @@
import copy
import datetime
import inspect
+import re
import sys
import time
@@ -55,6 +56,17 @@ import proxy
import ticks
from util import *
+import SimObject
+
+def isSimObject(*args, **kwargs):
+ return SimObject.isSimObject(*args, **kwargs)
+
+def isSimObjectSequence(*args, **kwargs):
+ return SimObject.isSimObjectSequence(*args, **kwargs)
+
+def isSimObjectClass(*args, **kwargs):
+ return SimObject.isSimObjectClass(*args, **kwargs)
+
# Dummy base class to identify types that are legitimate for SimObject
# parameters.
class ParamValue(object):
@@ -108,14 +120,15 @@ class ParamDesc(object):
def __getattr__(self, attr):
if attr == 'ptype':
try:
- ptype = eval(self.ptype_str, objects.__dict__)
+ ptype = SimObject.allClasses[self.ptype_str]
if not isinstance(ptype, type):
raise NameError
self.ptype = ptype
return ptype
except NameError:
- raise TypeError, \
- "Param qualifier '%s' is not a type" % self.ptype_str
+ raise
+ #raise TypeError, \
+ # "Param qualifier '%s' is not a type" % self.ptype_str
raise AttributeError, "'%s' object has no attribute '%s'" % \
(type(self).__name__, attr)
@@ -150,6 +163,9 @@ class VectorParamValue(list):
def ini_str(self):
return ' '.join([v.ini_str() for v in self])
+ def getValue(self):
+ return [ v.getValue() for v in self ]
+
def unproxy(self, base):
return [v.unproxy(base) for v in self]
@@ -165,20 +181,26 @@ class VectorParamDesc(ParamDesc):
if isinstance(value, (list, tuple)):
# list: coerce each element into new list
tmp_list = [ ParamDesc.convert(self, v) for v in value ]
- if isSimObjectSequence(tmp_list):
- return SimObjVector(tmp_list)
- else:
- return VectorParamValue(tmp_list)
else:
- # singleton: leave it be (could coerce to a single-element
- # list here, but for some historical reason we don't...
- return ParamDesc.convert(self, value)
+ # singleton: coerce to a single-element list
+ tmp_list = [ ParamDesc.convert(self, value) ]
- def cxx_predecls(self):
- return ['#include <vector>'] + self.ptype.cxx_predecls
+ if isSimObjectSequence(tmp_list):
+ return SimObjVector(tmp_list)
+ else:
+ return VectorParamValue(tmp_list)
def swig_predecls(self):
- return ['%include "std_vector.i"'] + self.ptype.swig_predecls
+ return ['%%include "%s_vptype.i"' % self.ptype_str]
+
+ def swig_decl(self):
+ cxx_type = re.sub('std::', '', self.ptype.cxx_type)
+ vdecl = 'namespace std { %%template(vector_%s) vector< %s >; }' % \
+ (self.ptype_str, cxx_type)
+ return ['%include "std_vector.i"'] + self.ptype.swig_predecls + [vdecl]
+
+ def cxx_predecls(self):
+ return ['#include <vector>'] + self.ptype.cxx_predecls
def cxx_decl(self):
return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
@@ -232,7 +254,10 @@ class String(ParamValue,str):
cxx_predecls = ['#include <string>']
swig_predecls = ['%include "std_string.i"\n' +
'%apply const std::string& {std::string *};']
- pass
+ swig_predecls = ['%include "std_string.i"' ]
+
+ def getValue(self):
+ return self
# superclass for "numeric" parameter values, to emulate math
# operations in a type-safe way. e.g., a Latency times an int returns
@@ -291,7 +316,7 @@ class CheckedIntType(type):
if not cls.swig_predecls:
# most derived types require this, so we just do it here once
- cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
+ cls.swig_predecls = ['%import "stdint.i"\n' +
'%import "sim/host.hh"']
if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
@@ -328,6 +353,9 @@ class CheckedInt(NumericParamValue):
% type(value).__name__
self._check()
+ def getValue(self):
+ return long(self.value)
+
class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
@@ -350,6 +378,9 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
class Float(ParamValue, float):
cxx_type = 'double'
+ def getValue(self):
+ return float(self.value)
+
class MemorySize(CheckedInt):
cxx_type = 'uint64_t'
size = 64
@@ -374,7 +405,7 @@ class MemorySize32(CheckedInt):
class Addr(CheckedInt):
cxx_type = 'Addr'
- cxx_predecls = ['#include "targetarch/isa_traits.hh"']
+ cxx_predecls = ['#include "arch/isa_traits.hh"']
size = 64
unsigned = True
def __init__(self, value):
@@ -443,9 +474,27 @@ class Range(ParamValue):
class AddrRange(Range):
type = Addr
+ swig_predecls = ['%include "python/swig/range.i"']
+
+ def getValue(self):
+ from m5.objects.params import AddrRange
+
+ value = AddrRange()
+ value.start = long(self.first)
+ value.end = long(self.second)
+ return value
class TickRange(Range):
type = Tick
+ swig_predecls = ['%include "python/swig/range.i"']
+
+ def getValue(self):
+ from m5.objects.params import TickRange
+
+ value = TickRange()
+ value.start = long(self.first)
+ value.end = long(self.second)
+ return value
# Boolean parameter type. Python doesn't let you subclass bool, since
# it doesn't want to let you create multiple instances of True and
@@ -458,6 +507,9 @@ class Bool(ParamValue):
except TypeError:
self.value = bool(value)
+ def getValue(self):
+ return bool(self.value)
+
def __str__(self):
return str(self.value)
@@ -489,7 +541,7 @@ def NextEthernetAddr():
class EthernetAddr(ParamValue):
cxx_type = 'Net::EthAddr'
cxx_predecls = ['#include "base/inet.hh"']
- swig_predecls = ['class Net::EthAddr;']
+ swig_predecls = ['%include "python/swig/inet.i"']
def __init__(self, value):
if value == NextEthernetAddr:
self.value = value
@@ -513,6 +565,10 @@ class EthernetAddr(ParamValue):
return EthernetAddr(self.value())
return self
+ def getValue(self):
+ from m5.objects.params import EthAddr
+ return EthAddr(self.value)
+
def ini_str(self):
return self.value
@@ -555,13 +611,40 @@ def parse_time(value):
raise ValueError, "Could not parse '%s' as a time" % value
class Time(ParamValue):
- cxx_type = 'time_t'
+ cxx_type = 'tm'
+ cxx_predecls = [ '#include <time.h>' ]
+ swig_predecls = [ '%include "python/swig/time.i"' ]
def __init__(self, value):
self.value = parse_time(value)
+ def getValue(self):
+ from m5.objects.params import tm
+
+ c_time = tm()
+ py_time = self.value
+
+ # UNIX is years since 1900
+ c_time.tm_year = py_time.tm_year - 1900;
+
+ # Python starts at 1, UNIX starts at 0
+ c_time.tm_mon = py_time.tm_mon - 1;
+ c_time.tm_mday = py_time.tm_mday;
+ c_time.tm_hour = py_time.tm_hour;
+ c_time.tm_min = py_time.tm_min;
+ c_time.tm_sec = py_time.tm_sec;
+
+ # Python has 0 as Monday, UNIX is 0 as sunday
+ c_time.tm_wday = py_time.tm_wday + 1
+ if c_time.tm_wday > 6:
+ c_time.tm_wday -= 7;
+
+ # Python starts at 1, Unix starts at 0
+ c_time.tm_yday = py_time.tm_yday - 1;
+
+ return c_time
+
def __str__(self):
- tm = self.value
- return ' '.join([ str(tm[i]) for i in xrange(8)])
+ return time.asctime(self.value)
def ini_str(self):
return str(self)
@@ -580,9 +663,16 @@ class Time(ParamValue):
# classes (_ListEnum and _DictEnum) to serve as base classes, then
# derive the new type from the appropriate base class on the fly.
-
+allEnums = {}
# Metaclass for Enum types
class MetaEnum(type):
+ def __new__(mcls, name, bases, dict):
+ assert name not in allEnums
+
+ cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
+ allEnums[name] = cls
+ return cls
+
def __init__(cls, name, bases, init_dict):
if init_dict.has_key('map'):
if not isinstance(cls.map, dict):
@@ -603,18 +693,42 @@ class MetaEnum(type):
raise TypeError, "Enum-derived class must define "\
"attribute 'map' or 'vals'"
- cls.cxx_type = name + '::Enum'
+ cls.cxx_type = 'Enums::%s' % name
super(MetaEnum, cls).__init__(name, bases, init_dict)
+ def __str__(cls):
+ return cls.__name__
+
# Generate C++ class declaration for this enum type.
# Note that we wrap the enum in a class/struct to act as a namespace,
# so that the enum strings can be brief w/o worrying about collisions.
def cxx_decl(cls):
- s = 'struct %s {\n enum Enum {\n ' % cls.__name__
- s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
- s += '\n };\n};\n'
- return s
+ code = "#ifndef __ENUM__%s\n" % cls
+ code += '#define __ENUM__%s\n' % cls
+ code += '\n'
+ code += 'namespace Enums {\n'
+ code += ' enum %s {\n' % cls
+ for val in cls.vals:
+ code += ' %s = %d,\n' % (val, cls.map[val])
+ code += ' Num_%s = %d,\n' % (cls, len(cls.vals))
+ code += ' };\n'
+ code += ' extern const char *%sStrings[Num_%s];\n' % (cls, cls)
+ code += '}\n'
+ code += '\n'
+ code += '#endif\n'
+ return code
+
+ def cxx_def(cls):
+ code = '#include "enums/%s.hh"\n' % cls
+ code += 'namespace Enums {\n'
+ code += ' const char *%sStrings[Num_%s] =\n' % (cls, cls)
+ code += ' {\n'
+ for val in cls.vals:
+ code += ' "%s",\n' % val
+ code += ' };\n'
+ code += '}\n'
+ return code
# Base class for enum types.
class Enum(ParamValue):
@@ -627,6 +741,9 @@ class Enum(ParamValue):
% (value, self.vals)
self.value = value
+ def getValue(self):
+ return int(self.map[self.value])
+
def __str__(self):
return self.value
@@ -636,9 +753,12 @@ frequency_tolerance = 0.001 # 0.1%
class TickParamValue(NumericParamValue):
cxx_type = 'Tick'
cxx_predecls = ['#include "sim/host.hh"']
- swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
+ swig_predecls = ['%import "stdint.i"\n' +
'%import "sim/host.hh"']
+ def getValue(self):
+ return long(self.value)
+
class Latency(TickParamValue):
def __init__(self, value):
if isinstance(value, (Latency, Clock)):
@@ -661,12 +781,16 @@ class Latency(TickParamValue):
return Frequency(self)
raise AttributeError, "Latency object has no attribute '%s'" % attr
- # convert latency to ticks
- def ini_str(self):
+ def getValue(self):
if self.ticks or self.value == 0:
- return '%d' % self.value
+ value = self.value
else:
- return '%d' % (ticks.fromSeconds(self.value))
+ value = ticks.fromSeconds(self.value)
+ return long(value)
+
+ # convert latency to ticks
+ def ini_str(self):
+ return '%d' % self.getValue()
class Frequency(TickParamValue):
def __init__(self, value):
@@ -691,11 +815,15 @@ class Frequency(TickParamValue):
raise AttributeError, "Frequency object has no attribute '%s'" % attr
# convert latency to ticks
- def ini_str(self):
+ def getValue(self):
if self.ticks or self.value == 0:
- return '%d' % self.value
+ value = self.value
else:
- return '%d' % (ticks.fromSeconds(1.0 / self.value))
+ value = ticks.fromSeconds(1.0 / self.value)
+ return long(value)
+
+ def ini_str(self):
+ return '%d' % self.getValue()
# A generic frequency and/or Latency value. Value is stored as a latency,
# but to avoid ambiguity this object does not support numeric ops (* or /).
@@ -703,7 +831,7 @@ class Frequency(TickParamValue):
class Clock(ParamValue):
cxx_type = 'Tick'
cxx_predecls = ['#include "sim/host.hh"']
- swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
+ swig_predecls = ['%import "stdint.i"\n' +
'%import "sim/host.hh"']
def __init__(self, value):
if isinstance(value, (Latency, Clock)):
@@ -726,6 +854,9 @@ class Clock(ParamValue):
return Latency(self)
raise AttributeError, "Frequency object has no attribute '%s'" % attr
+ def getValue(self):
+ return self.period.getValue()
+
def ini_str(self):
return self.period.ini_str()
@@ -739,11 +870,15 @@ class NetworkBandwidth(float,ParamValue):
def __str__(self):
return str(self.val)
- def ini_str(self):
+ def getValue(self):
# convert to seconds per byte
value = 8.0 / float(self)
# convert to ticks per byte
- return '%f' % (ticks.fromSeconds(value))
+ value = ticks.fromSeconds(value)
+ return float(value)
+
+ def ini_str(self):
+ return '%f' % self.getValue()
class MemoryBandwidth(float,ParamValue):
cxx_type = 'float'
@@ -755,11 +890,15 @@ class MemoryBandwidth(float,ParamValue):
def __str__(self):
return str(self.val)
- def ini_str(self):
+ def getValue(self):
# convert to seconds per byte
value = 1.0 / float(self)
# convert to ticks per byte
- return '%f' % (ticks.fromSeconds(value))
+ value = ticks.fromSeconds(value)
+ return float(value)
+
+ def ini_str(self):
+ return '%f' % self.getValue()
#
# "Constants"... handy aliases for various values.
@@ -786,9 +925,13 @@ class NullSimObject(object):
def set_path(self, parent, name):
pass
+
def __str__(self):
return 'Null'
+ def getValue(self):
+ return None
+
# The only instance you'll ever need...
NULL = NullSimObject()
@@ -882,6 +1025,8 @@ class PortRef(object):
# Call C++ to create corresponding port connection between C++ objects
def ccConnect(self):
+ import internal
+
if self.ccConnected: # already done this
return
peer = self.peer
@@ -1006,7 +1151,6 @@ class PortParamDesc(object):
ptype_str = 'Port'
ptype = Port
-
__all__ = ['Param', 'VectorParam',
'Enum', 'Bool', 'String', 'Float',
'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
@@ -1021,8 +1165,3 @@ __all__ = ['Param', 'VectorParam',
'Time',
'NextEthernetAddr', 'NULL',
'Port', 'VectorPort']
-
-# see comment on imports at end of __init__.py.
-from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass
-import objects
-import internal
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
new file mode 100644
index 000000000..1ef78d6cb
--- /dev/null
+++ b/src/python/m5/simulate.py
@@ -0,0 +1,199 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# 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.
+#
+# Authors: Nathan Binkert
+# Steve Reinhardt
+
+import atexit
+import os
+import sys
+
+# import the SWIG-wrapped main C++ functions
+import internal
+from main import options
+import SimObject
+import ticks
+
+# The final hook to generate .ini files. Called from the user script
+# once the config is built.
+def instantiate(root):
+ # we need to fix the global frequency
+ ticks.fixGlobalFrequency()
+
+ root.unproxy_all()
+ # ugly temporary hack to get output to config.ini
+ sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w')
+ root.print_ini()
+ sys.stdout.close() # close config.ini
+ sys.stdout = sys.__stdout__ # restore to original
+
+ # Initialize the global statistics
+ internal.stats.initSimStats()
+
+ # Create the C++ sim objects and connect ports
+ root.createCCObject()
+ root.connectPorts()
+
+ # Do a second pass to finish initializing the sim objects
+ internal.sim_object.initAll()
+
+ # Do a third pass to initialize statistics
+ internal.sim_object.regAllStats()
+
+ # Check to make sure that the stats package is properly initialized
+ internal.stats.check()
+
+ # Reset to put the stats in a consistent state.
+ internal.stats.reset()
+
+def doDot(root):
+ dot = pydot.Dot()
+ instance.outputDot(dot)
+ dot.orientation = "portrait"
+ dot.size = "8.5,11"
+ dot.ranksep="equally"
+ dot.rank="samerank"
+ dot.write("config.dot")
+ dot.write_ps("config.ps")
+
+need_resume = []
+need_startup = True
+def simulate(*args, **kwargs):
+ global need_resume, need_startup
+
+ if need_startup:
+ internal.core.SimStartup()
+ need_startup = False
+
+ for root in need_resume:
+ resume(root)
+ need_resume = []
+
+ return internal.event.simulate(*args, **kwargs)
+
+# Export curTick to user script.
+def curTick():
+ return internal.core.cvar.curTick
+
+# Python exit handlers happen in reverse order. We want to dump stats last.
+atexit.register(internal.stats.dump)
+
+# register our C++ exit callback function with Python
+atexit.register(internal.core.doExitCleanup)
+
+# This loops until all objects have been fully drained.
+def doDrain(root):
+ all_drained = drain(root)
+ while (not all_drained):
+ all_drained = drain(root)
+
+# Tries to drain all objects. Draining might not be completed unless
+# all objects return that they are drained on the first call. This is
+# because as objects drain they may cause other objects to no longer
+# be drained.
+def drain(root):
+ all_drained = False
+ drain_event = internal.event.createCountedDrain()
+ unready_objects = root.startDrain(drain_event, True)
+ # If we've got some objects that can't drain immediately, then simulate
+ if unready_objects > 0:
+ drain_event.setCount(unready_objects)
+ simulate()
+ else:
+ all_drained = True
+ internal.event.cleanupCountedDrain(drain_event)
+ return all_drained
+
+def resume(root):
+ root.resume()
+
+def checkpoint(root, dir):
+ if not isinstance(root, objects.Root):
+ raise TypeError, "Checkpoint must be called on a root object."
+ doDrain(root)
+ print "Writing checkpoint"
+ internal.sim_object.serializeAll(dir)
+ resume(root)
+
+def restoreCheckpoint(root, dir):
+ print "Restoring from checkpoint"
+ internal.sim_object.unserializeAll(dir)
+ need_resume.append(root)
+
+def changeToAtomic(system):
+ if not isinstance(system, (objects.Root, objects.System)):
+ raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
+ (type(system), objects.Root, objects.System)
+ if system.getMemoryMode() != internal.sim_object.SimObject.Atomic:
+ doDrain(system)
+ print "Changing memory mode to atomic"
+ system.changeTiming(internal.sim_object.SimObject.Atomic)
+
+def changeToTiming(system):
+ if not isinstance(system, (objects.Root, objects.System)):
+ raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
+ (type(system), objects.Root, objects.System)
+
+ if system.getMemoryMode() != internal.sim_object.SimObject.Timing:
+ doDrain(system)
+ print "Changing memory mode to timing"
+ system.changeTiming(internal.sim_object.SimObject.Timing)
+
+def switchCpus(cpuList):
+ print "switching cpus"
+ if not isinstance(cpuList, list):
+ raise RuntimeError, "Must pass a list to this function"
+ for i in cpuList:
+ if not isinstance(i, tuple):
+ raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
+
+ [old_cpus, new_cpus] = zip(*cpuList)
+
+ for cpu in old_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU" % cpu
+ for cpu in new_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU" % cpu
+
+ # Drain all of the individual CPUs
+ drain_event = internal.event.createCountedDrain()
+ unready_cpus = 0
+ for old_cpu in old_cpus:
+ unready_cpus += old_cpu.startDrain(drain_event, False)
+ # If we've got some objects that can't drain immediately, then simulate
+ if unready_cpus > 0:
+ drain_event.setCount(unready_cpus)
+ simulate()
+ internal.event.cleanupCountedDrain(drain_event)
+ # Now all of the CPUs are ready to be switched out
+ for old_cpu in old_cpus:
+ old_cpu._ccObject.switchOut()
+ index = 0
+ for new_cpu in new_cpus:
+ new_cpu.takeOverFrom(old_cpus[index])
+ new_cpu._ccObject.resume()
+ index += 1
diff --git a/src/python/m5/ticks.py b/src/python/m5/ticks.py
index e91b470ff..91834c9c8 100644
--- a/src/python/m5/ticks.py
+++ b/src/python/m5/ticks.py
@@ -28,14 +28,12 @@
import sys
-import convert
-import internal
-
tps = 1.0e12 # default to 1 THz (1 Tick == 1 ps)
tps_fixed = False # once set to true, can't be changed
# fix the global frequency and tell C++ about it
def fixGlobalFrequency():
+ import internal
global tps, tps_fixed
if not tps_fixed:
tps_fixed = True
@@ -43,6 +41,8 @@ def fixGlobalFrequency():
print "Global frequency set at %d ticks per second" % int(tps)
def setGlobalFrequency(ticksPerSecond):
+ import convert
+
global tps, tps_fixed
if tps_fixed: