diff options
author | Ali Saidi <saidi@eecs.umich.edu> | 2005-03-14 15:38:26 -0500 |
---|---|---|
committer | Ali Saidi <saidi@eecs.umich.edu> | 2005-03-14 15:38:26 -0500 |
commit | 76e6dd01ae4a534adad1d34398fefc819771a781 (patch) | |
tree | a678ca355625b9199cbb0f64ca42d247e520accb | |
parent | c1f5b983f0c8cece7a8387b05b40889c9520fb39 (diff) | |
parent | bc2923f78d739ad5ff42dee402c5ba27c02004f1 (diff) | |
download | gem5-76e6dd01ae4a534adad1d34398fefc819771a781.tar.xz |
Merge zizzer:/bk/m5 into zeep.eecs.umich.edu:/z/saidi/work/m5
--HG--
extra : convert_revision : 9eed6f31249ff099464044b32b882b3cc041b57a
-rw-r--r-- | SConscript | 2 | ||||
-rw-r--r-- | build/SConstruct | 5 | ||||
-rw-r--r-- | dev/pciconfigall.cc | 5 | ||||
-rw-r--r-- | python/SConscript | 39 | ||||
-rw-r--r-- | python/m5/__init__.py | 34 | ||||
-rw-r--r-- | python/m5/config.py | 236 | ||||
-rw-r--r-- | python/m5/objects/BaseCPU.mpy | 2 | ||||
-rw-r--r-- | python/m5/smartdict.py | 23 | ||||
-rw-r--r-- | sim/sim_object.hh | 4 | ||||
-rwxr-xr-x | test/genini.py | 5 |
10 files changed, 224 insertions, 131 deletions
diff --git a/SConscript b/SConscript index cff240a69..3b3c871bc 100644 --- a/SConscript +++ b/SConscript @@ -378,7 +378,7 @@ env.Command(Split('''arch/alpha/decoder.cc # header files into a place where they can be found. SConscript('libelf/SConscript-local', exports = 'env', duplicate=0) SConscript('python/SConscript', exports = ['env'], duplicate=0) - +SConscript('simobj/SConscript', exports = 'env', duplicate=0) # This function adds the specified sources to the given build # environment, and returns a list of all the corresponding SCons diff --git a/build/SConstruct b/build/SConstruct index 3d7db1db2..e33373243 100644 --- a/build/SConstruct +++ b/build/SConstruct @@ -62,6 +62,9 @@ if not os.path.isdir('ext'): % EXT_SRCDIR sys.exit(1) +# tell python where to find m5 python code +sys.path.append(os.path.join(SRCDIR, 'python')) + ################################################### # @@ -289,7 +292,7 @@ for build_dir in build_dirs: ################################################### # # Let SCons do its thing. At this point SCons will use the defined -# build enviornments to build the requested targets. +# build environments to build the requested targets. # ################################################### diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc index 1a9804f79..2cbd5adc0 100644 --- a/dev/pciconfigall.cc +++ b/dev/pciconfigall.cc @@ -98,11 +98,12 @@ PciConfigAll::startup() Fault PciConfigAll::read(MemReqPtr &req, uint8_t *data) { - DPRINTF(PciConfigAll, "read va=%#x size=%d\n", - req->vaddr, req->size); Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); + DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", + req->vaddr, daddr, req->size); + int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; int reg = daddr & 0xFF; diff --git a/python/SConscript b/python/SConscript index 81bc52286..9c15c6d50 100644 --- a/python/SConscript +++ b/python/SConscript @@ -26,7 +26,11 @@ # (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 os, os.path, re +import os, os.path, re, sys + +Import('env') + +import m5scons def WriteEmbeddedPyFile(target, source, path, name, ext, filename): if isinstance(source, str): @@ -89,7 +93,6 @@ def splitpath(path): path.insert(0, base) return path, file -Import('env') def MakeEmbeddedPyFile(target, source, env): target = file(str(target[0]), 'w') @@ -145,27 +148,11 @@ def MakeEmbeddedPyFile(target, source, env): WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename) def MakeDefinesPyFile(target, source, env): - target = file(str(target[0]), 'w') - - print >>target, "import os" - defines = env['CPPDEFINES'] - if isinstance(defines, list): - for var in defines: - if isinstance(var, tuple): - key,val = var - else: - key,val = var,'True' - - if not isinstance(key, basestring): - panic("invalid type for define: %s" % type(key)) - - print >>target, "os.environ['%s'] = '%s'" % (key, val) - - elif isinstance(defines, dict): - for key,val in defines.iteritems(): - print >>target, "os.environ['%s'] = '%s'" % (key, val) - else: - panic("invalid type for defines: %s" % type(defines)) + f = file(str(target[0]), 'w') + print >>f, "import __main__" + print >>f, "__main__.m5_build_env = ", + print >>f, m5scons.flatten_defines(env['CPPDEFINES']) + f.close() CFileCounter = 0 def MakePythonCFile(target, source, env): @@ -193,8 +180,10 @@ EmbedMap %(name)s("%(fname)s", /* namespace */ } ''' -embedded_py_files = [ 'mpy_importer.py', '../util/pbs/jobfile.py' ] -objpath = os.path.join(env['SRCDIR'], 'python/m5') +# base list of .py files to embed +embedded_py_files = [ '../util/pbs/jobfile.py' ] +# add all .py and .mpy files in python/m5 +objpath = os.path.join(env['SRCDIR'], 'python', 'm5') for root, dirs, files in os.walk(objpath, topdown=True): for i,dir in enumerate(dirs): if dir == 'SCCS': diff --git a/python/m5/__init__.py b/python/m5/__init__.py index 7cb3a32c6..16f48dba3 100644 --- a/python/m5/__init__.py +++ b/python/m5/__init__.py @@ -1,7 +1,37 @@ -from mpy_importer import * +import sys, os + +# the mpy import code is added to the global import meta_path as a +# side effect of this import +from mpy_importer import AddToPath, LoadMpyFile + +# define this here so we can use it right away if necessary +def panic(string): + print >>sys.stderr, 'panic:', string + sys.exit(1) + +# find the m5 compile options: must be specified as a dict in +# __main__.m5_build_env. +import __main__ +if not hasattr(__main__, 'm5_build_env'): + panic("__main__ must define m5_build_env") + +# make a SmartDict out of the build options for our local use +import smartdict +build_env = smartdict.SmartDict() +build_env.update(__main__.m5_build_env) + +# make a SmartDict out of the OS environment too +env = smartdict.SmartDict() +env.update(os.environ) + +# import the main m5 config code from config import * +config.add_param_types(config) + +# import the built-in object definitions from objects import * +config.add_param_types(objects) -cpp_classes = MetaSimObject.cpp_classes +cpp_classes = config.MetaSimObject.cpp_classes cpp_classes.sort() diff --git a/python/m5/config.py b/python/m5/config.py index 2c5a70b25..a9d7a2f41 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -27,8 +27,6 @@ from __future__ import generators import os, re, sys, types, inspect -from mpy_importer import AddToPath, LoadMpyFile -from smartdict import SmartDict from convert import * noDot = False @@ -37,13 +35,6 @@ try: except: noDot = True -env = SmartDict() -env.update(os.environ) - -def panic(string): - print >>sys.stderr, 'panic:', string - sys.exit(1) - def issequence(value): return isinstance(value, tuple) or isinstance(value, list) @@ -210,6 +201,28 @@ class_decorator = 'M5M5_SIMOBJECT_' expr_decorator = 'M5M5_EXPRESSION_' dot_decorator = '_M5M5_DOT_' +# 'Global' map of legitimate types for SimObject parameters. +param_types = {} + +# Dummy base class to identify types that are legitimate for SimObject +# parameters. +class ParamType(object): + pass + +# Add types defined in given context (dict or module) that are derived +# from ParamType to param_types map. +def add_param_types(ctx): + if isinstance(ctx, types.DictType): + source_dict = ctx + elif isinstance(ctx, types.ModuleType): + source_dict = ctx.__dict__ + else: + raise TypeError, \ + "m5.config.add_param_types requires dict or module as arg" + for key,val in source_dict.iteritems(): + if isinstance(val, type) and issubclass(val, ParamType): + param_types[key] = val + # The metaclass for ConfigNode (and thus for everything that derives # from ConfigNode, including SimObject). This class controls how new # classes that derive from ConfigNode are instantiated, and provides @@ -247,7 +260,7 @@ class MetaConfigNode(type): # initialize required attributes cls._params = {} cls._values = {} - cls._enums = {} + cls._param_types = {} cls._bases = [c for c in cls.__mro__ if isConfigNode(c)] cls._anon_subclass_counter = 0 @@ -270,19 +283,26 @@ class MetaConfigNode(type): elif isNullPointer(val): cls._values[key] = val - # now process _init_dict items + # process param types from _init_dict, as these may be needed + # by param descriptions also in _init_dict for key,val in cls._init_dict.items(): + if isinstance(val, type) and issubclass(val, ParamType): + cls._param_types[key] = val + if not issubclass(val, ConfigNode): + del cls._init_dict[key] + + # now process remaining _init_dict items + for key,val in cls._init_dict.items(): + # param descriptions if isinstance(val, _Param): cls._params[key] = val + # try to resolve local param types in local param_types scope + val.maybe_resolve_type(cls._param_types) # init-time-only keywords elif cls.init_keywords.has_key(key): cls._set_keyword(key, val, cls.init_keywords[key]) - # enums - elif isinstance(val, type) and issubclass(val, Enum): - cls._enums[key] = val - # See description of decorators in the importer.py file. # We just strip off the expr_decorator now since we don't # need from this point on. @@ -419,7 +439,11 @@ class MetaConfigNode(type): # It's ok: set attribute by delegating to 'object' class. # Note the use of param.make_value() to verify/canonicalize # the assigned value - param.valid(value) + try: + param.valid(value) + except: + panic("Error setting param %s.%s to %s\n" % \ + (cls.__name__, attr, value)) cls._setvalue(attr, value) elif isConfigNode(value) or isSimObjSequence(value): cls._setvalue(attr, value) @@ -562,7 +586,7 @@ class MetaSimObject(MetaConfigNode): def _cpp_decl(cls): name = cls.__name__ code = "" - code += "\n".join([e.cpp_declare() for e in cls._enums.values()]) + code += "\n".join([e.cpp_declare() for e in cls._param_types.values()]) code += "\n" param_names = cls._params.keys() param_names.sort() @@ -854,13 +878,24 @@ class _Param(object): if not hasattr(self, 'desc'): raise TypeError, 'desc attribute missing' + def maybe_resolve_type(self, context): + # check if already resolved... don't use hasattr(), + # as that calls __getattr__() + if self.__dict__.has_key('ptype'): + return + try: + self.ptype = context[self.ptype_string] + except KeyError: + # no harm in trying... we'll try again later using global scope + pass + def __getattr__(self, attr): if attr == 'ptype': try: - self.ptype = eval(self.ptype_string) + self.ptype = param_types[self.ptype_string] return self.ptype except: - raise TypeError, 'Param.%s: undefined type' % self.ptype_string + panic("undefined Param type %s" % self.ptype_string) else: raise AttributeError, "'%s' object has no attribute '%s'" % \ (type(self).__name__, attr) @@ -887,19 +922,10 @@ class _ParamProxy(object): # E.g., Param.Int(5, "number of widgets") def __call__(self, *args, **kwargs): - # Param type could be defined only in context of caller (e.g., - # for locally defined Enum subclass). Need to go look up the - # type in that enclosing scope. - caller_frame = inspect.stack()[1][0] - ptype = caller_frame.f_locals.get(self.ptype, None) - if not ptype: ptype = caller_frame.f_globals.get(self.ptype, None) - if not ptype: ptype = globals().get(self.ptype, None) - # ptype could still be None due to circular references... we'll - # try one more time to evaluate lazily when ptype is first needed. - # In the meantime we'll save the type name as a string. - if not ptype: ptype = self.ptype - return _Param(ptype, *args, **kwargs) + return _Param(self.ptype, *args, **kwargs) + # Strange magic to theoretically allow dotted names as Param classes, + # e.g., Param.Foo.Bar(...) to have a param of type Foo.Bar def __getattr__(self, attr): if attr == '__bases__': raise AttributeError, '' @@ -975,8 +1001,33 @@ VectorParam = _VectorParamProxy(None) # to correspond to distinct C++ types as well. # ##################################################################### -# Integer parameter type. -class _CheckedInt(object): + + +# Metaclass for bounds-checked integer parameters. See CheckedInt. +class CheckedIntType(type): + def __init__(cls, name, bases, dict): + super(CheckedIntType, cls).__init__(name, bases, dict) + + # CheckedInt is an abstract base class, so we actually don't + # want to do any processing on it... the rest of this code is + # just for classes that derive from CheckedInt. + if name == 'CheckedInt': + return + + if not (hasattr(cls, 'min') and hasattr(cls, 'max')): + if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): + panic("CheckedInt subclass %s must define either\n" \ + " 'min' and 'max' or 'size' and 'unsigned'\n" \ + % name); + if cls.unsigned: + cls.min = 0 + cls.max = 2 ** cls.size - 1 + else: + cls.min = -(2 ** (cls.size - 1)) + cls.max = (2 ** (cls.size - 1)) - 1 + + cls._cpp_param_decl = cls.cppname + def _convert(cls, value): if isinstance(value, bool): return int(value) @@ -987,86 +1038,72 @@ class _CheckedInt(object): if isinstance(value, (str, float)): value = long(float(value)) - if not cls._min <= value <= cls._max: + if not cls.min <= value <= cls.max: raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ - (cls._min, value, cls._max) + (cls.min, value, cls.max) return value - _convert = classmethod(_convert) def _string(cls, value): return str(value) - _string = classmethod(_string) - -class CheckedInt(type): - def __new__(cls, cppname, min, max): - # New class derives from _CheckedInt base with proper bounding - # parameters - dict = { '_cpp_param_decl' : cppname, '_min' : min, '_max' : max } - return type.__new__(cls, cppname, (_CheckedInt, ), dict) - -class CheckedIntType(CheckedInt): - def __new__(cls, cppname, size, unsigned): - dict = {} - if unsigned: - min = 0 - max = 2 ** size - 1 - else: - min = -(2 ** (size - 1)) - max = (2 ** (size - 1)) - 1 - return super(cls, CheckedIntType).__new__(cls, cppname, min, max) +# Abstract superclass for bounds-checked integer parameters. This +# class is subclassed to generate parameter classes with specific +# bounds. Initialization of the min and max bounds is done in the +# metaclass CheckedIntType.__init__. +class CheckedInt(ParamType): + __metaclass__ = CheckedIntType -Int = CheckedIntType('int', 32, False) -Unsigned = CheckedIntType('unsigned', 32, True) +class Int(CheckedInt): cppname = 'int'; size = 32; unsigned = False +class Unsigned(CheckedInt): cppname = 'unsigned'; size = 32; unsigned = True -Int8 = CheckedIntType('int8_t', 8, False) -UInt8 = CheckedIntType('uint8_t', 8, True) -Int16 = CheckedIntType('int16_t', 16, False) -UInt16 = CheckedIntType('uint16_t', 16, True) -Int32 = CheckedIntType('int32_t', 32, False) -UInt32 = CheckedIntType('uint32_t', 32, True) -Int64 = CheckedIntType('int64_t', 64, False) -UInt64 = CheckedIntType('uint64_t', 64, True) +class Int8(CheckedInt): cppname = 'int8_t'; size = 8; unsigned = False +class UInt8(CheckedInt): cppname = 'uint8_t'; size = 8; unsigned = True +class Int16(CheckedInt): cppname = 'int16_t'; size = 16; unsigned = False +class UInt16(CheckedInt): cppname = 'uint16_t'; size = 16; unsigned = True +class Int32(CheckedInt): cppname = 'int32_t'; size = 32; unsigned = False +class UInt32(CheckedInt): cppname = 'uint32_t'; size = 32; unsigned = True +class Int64(CheckedInt): cppname = 'int64_t'; size = 64; unsigned = False +class UInt64(CheckedInt): cppname = 'uint64_t'; size = 64; unsigned = True -Counter = CheckedIntType('Counter', 64, True) -Addr = CheckedIntType('Addr', 64, True) -Tick = CheckedIntType('Tick', 64, True) +class Counter(CheckedInt): cppname = 'Counter'; size = 64; unsigned = True +class Addr(CheckedInt): cppname = 'Addr'; size = 64; unsigned = True +class Tick(CheckedInt): cppname = 'Tick'; size = 64; unsigned = True -Percent = CheckedInt('int', 0, 100) +class Percent(CheckedInt): cppname = 'int'; min = 0; max = 100 class Pair(object): def __init__(self, first, second): self.first = first self.second = second -class _Range(object): +class MetaRange(type): + def __init__(cls, name, bases, dict): + super(MetaRange, cls).__init__(name, bases, dict) + if name == 'Range': + return + cls._cpp_param_decl = 'Range<%s>' % cls.type._cpp_param_decl + def _convert(cls, value): if not isinstance(value, Pair): raise TypeError, 'value %s is not a Pair' % value - return Pair(cls._type._convert(value.first), - cls._type._convert(value.second)) - _convert = classmethod(_convert) + return Pair(cls.type._convert(value.first), + cls.type._convert(value.second)) def _string(cls, value): - return '%s:%s' % (cls._type._string(value.first), - cls._type._string(value.second)) - _string = classmethod(_string) + return '%s:%s' % (cls.type._string(value.first), + cls.type._string(value.second)) + +class Range(ParamType): + __metaclass__ = MetaRange def RangeSize(start, size): return Pair(start, start + size - 1) -class Range(type): - def __new__(cls, type): - dict = { '_cpp_param_decl' : 'Range<%s>' % type._cpp_param_decl, - '_type' : type } - clsname = 'Range_' + type.__name__ - return super(cls, Range).__new__(cls, clsname, (_Range, ), dict) - -AddrRange = Range(Addr) +class AddrRange(Range): type = Addr # Boolean parameter type. -class Bool(object): +class Bool(ParamType): _cpp_param_decl = 'bool' def _convert(value): t = type(value) @@ -1094,7 +1131,7 @@ class Bool(object): _string = staticmethod(_string) # String-valued parameter. -class String(object): +class String(ParamType): _cpp_param_decl = 'string' # Constructor. Value must be Python string. @@ -1134,7 +1171,7 @@ class NextEthernetAddr(object): self.value = self.addr self.addr = IncEthernetAddr(self.addr, inc) -class EthernetAddr(object): +class EthernetAddr(ParamType): _cpp_param_decl = 'EthAddr' def _convert(cls, value): @@ -1241,7 +1278,7 @@ class MetaEnum(type): return s # Base class for enum types. -class Enum(object): +class Enum(ParamType): __metaclass__ = MetaEnum vals = [] @@ -1261,8 +1298,8 @@ class Enum(object): # # Some memory range specifications use this as a default upper bound. -MAX_ADDR = Addr._max -MaxTick = Tick._max +MAX_ADDR = Addr.max +MaxTick = Tick.max # For power-of-two sizing, e.g. 64*K gives an integer value 65536. K = 1024 @@ -1274,9 +1311,6 @@ G = K*M # The final hook to generate .ini files. Called from configuration # script once config is built. def instantiate(root): - if not issubclass(root, Root): - raise AttributeError, 'Can only instantiate the Root of the tree' - instance = root.instantiate('root') instance.fixup() instance.display() @@ -1297,8 +1331,20 @@ def instantiate(root): # parameters to be set by keyword in the constructor. Note that most # of the heavy lifting for the SimObject param handling is done in the # MetaConfigNode metaclass. -class SimObject(ConfigNode): +class SimObject(ConfigNode, ParamType): __metaclass__ = MetaSimObject type = 'SimObject' -from objects import * + +# __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__ = ['issequence', + 'ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam', + 'Super', 'Enum', + 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', + 'Int32', 'UInt32', 'Int64', 'UInt64', + 'Counter', 'Addr', 'Tick', 'Percent', + 'Pair', 'RangeSize', 'AddrRange', 'MAX_ADDR', 'NULL', 'K', 'M', + 'NextEthernetAddr', + 'instantiate'] diff --git a/python/m5/objects/BaseCPU.mpy b/python/m5/objects/BaseCPU.mpy index be93e8ad1..5d8305d88 100644 --- a/python/m5/objects/BaseCPU.mpy +++ b/python/m5/objects/BaseCPU.mpy @@ -4,7 +4,7 @@ simobj BaseCPU(SimObject): icache = Param.BaseMem(NULL, "L1 instruction cache object") dcache = Param.BaseMem(NULL, "L1 data cache object") - if env.get('FULL_SYSTEM', 'False'): + if build_env['FULL_SYSTEM']: dtb = Param.AlphaDTB("Data TLB") itb = Param.AlphaITB("Instruction TLB") mem = Param.FunctionalMemory("memory") diff --git a/python/m5/smartdict.py b/python/m5/smartdict.py index e282bc07b..4ea8210d3 100644 --- a/python/m5/smartdict.py +++ b/python/m5/smartdict.py @@ -1,6 +1,23 @@ +# The SmartDict class fixes a couple of issues with using the content +# of os.environ or similar dicts of strings as Python variables: +# +# 1) Undefined variables should return False rather than raising KeyError. +# +# 2) String values of 'False', '0', etc., should evaluate to False +# (not just the empty string). +# +# #1 is solved by overriding __getitem__, and #2 is solved by using a +# proxy class for values and overriding __nonzero__ on the proxy. +# Everything else is just to (a) make proxies behave like normal +# values otherwise, (b) make sure any dict operation returns a proxy +# rather than a normal value, and (c) coerce values written to the +# dict to be strings. + + from convert import * class SmartDict(dict): + class Proxy(str): def __int__(self): return int(to_integer(str(self))) @@ -58,7 +75,7 @@ class SmartDict(dict): def __getitem__(self, key): - return self.Proxy(dict.__getitem__(self, key)) + return self.Proxy(dict.get(self, key, 'False')) def __setitem__(self, key, item): dict.__setitem__(self, key, str(item)) @@ -77,9 +94,9 @@ class SmartDict(dict): for key,value in dict.iteritems(self): yield key, self.Proxy(value) - def get(self, key, default=''): + def get(self, key, default='False'): return self.Proxy(dict.get(self, key, str(default))) - def setdefault(self, key, default=''): + def setdefault(self, key, default='False'): return self.Proxy(dict.setdefault(self, key, str(default))) diff --git a/sim/sim_object.hh b/sim/sim_object.hh index f4b316ebb..b8a3090ad 100644 --- a/sim/sim_object.hh +++ b/sim/sim_object.hh @@ -60,6 +60,10 @@ class SimObject : public Serializable, protected StartupCallback static SimObjectList simObjectList; public: + +// for Params struct +#include "simobj/param/SimObject.hh" + SimObject(const std::string &_name); virtual ~SimObject() {} diff --git a/test/genini.py b/test/genini.py index 025ba998a..b8eda5d46 100755 --- a/test/genini.py +++ b/test/genini.py @@ -35,6 +35,8 @@ sys.path.append(joinpath(mypath, '../util/pbs')) pathlist = [ '.' ] +m5_build_env = {} + try: opts, args = getopt.getopt(sys.argv[1:], '-E:I:') for opt,arg in opts: @@ -42,11 +44,12 @@ try: offset = arg.find('=') if offset == -1: name = arg - value = True + value = '1' else: name = arg[:offset] value = arg[offset+1:] os.environ[name] = value + m5_build_env[name] = value if opt == '-I': pathlist.append(arg) except getopt.GetoptError: |