blob: eead6ff5d53c9ece8a092ece5e4fbcc9ff9fa2d9 [file] [log] [blame]
# Copyright (c) 2004-2006 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
import imp
import py_compile
import sys
import zipfile
from os.path import basename
from os.path import exists
class DictImporter(object):
'''This importer takes a dictionary of arbitrary module names that
map to arbitrary filenames.'''
def __init__(self, modules, build_env):
self.modules = modules
self.installed = set()
self.build_env = build_env
def __del__(self):
self.unload()
def unload(self):
import sys
for module in self.installed:
del sys.modules[module]
self.installed = set()
def find_module(self, fullname, path):
if fullname == '__scons':
return self
if fullname == 'm5.objects':
return self
if fullname.startswith('m5.internal'):
return None
if fullname in self.modules and exists(self.modules[fullname]):
return self
return None
def load_module(self, fullname):
mod = imp.new_module(fullname)
sys.modules[fullname] = mod
self.installed.add(fullname)
mod.__loader__ = self
if fullname == 'm5.objects':
mod.__path__ = fullname.split('.')
return mod
if fullname == '__scons':
mod.__dict__['m5_build_env'] = self.build_env
return mod
srcfile = self.modules[fullname]
if basename(srcfile) == '__init__.py':
mod.__path__ = fullname.split('.')
mod.__file__ = srcfile
exec file(srcfile, 'r') in mod.__dict__
return mod
class ordered_dict(dict):
def keys(self):
keys = super(ordered_dict, self).keys()
keys.sort()
return keys
def values(self):
return [ self[key] for key in self.keys() ]
def items(self):
return [ (key,self[key]) for key in self.keys() ]
def iterkeys(self):
for key in self.keys():
yield key
def itervalues(self):
for value in self.values():
yield value
def iteritems(self):
for key,value in self.items():
yield key, value
class Generate(object):
def __init__(self, py_sources, sim_objects, build_env):
self.py_sources = py_sources
self.py_modules = {}
for source in py_sources:
self.py_modules[source.modpath] = source.srcpath
importer = DictImporter(self.py_modules, build_env)
# install the python importer so we can grab stuff from the source
# tree itself.
sys.meta_path[0:0] = [ importer ]
import m5
self.m5 = m5
# import all sim objects so we can populate the all_objects list
# make sure that we're working with a list, then let's sort it
sim_objects = list(sim_objects)
sim_objects.sort()
for simobj in sim_objects:
exec('from m5.objects import %s' % simobj)
# we need to unload all of the currently imported modules so that they
# will be re-imported the next time the sconscript is run
importer.unload()
sys.meta_path.remove(importer)
self.sim_objects = m5.SimObject.allClasses
self.enums = m5.params.allEnums
self.params = {}
for name,obj in self.sim_objects.iteritems():
for param in obj._params.local.values():
if not hasattr(param, 'swig_decl'):
continue
pname = param.ptype_str
if pname not in self.params:
self.params[pname] = param
def createSimObjectParam(self, target, source, env):
assert len(target) == 1 and len(source) == 1
hh_file = file(target[0].abspath, 'w')
name = str(source[0].get_contents())
obj = self.sim_objects[name]
print >>hh_file, obj.cxx_decl()
# Generate Python file containing a dict specifying the current
# build_env flags.
def makeDefinesPyFile(self, target, source, env):
f = file(str(target[0]), 'w')
print >>f, "m5_build_env = ", source[0]
f.close()
# Generate python file containing info about the M5 source code
def makeInfoPyFile(self, target, source, env):
f = file(str(target[0]), 'w')
for src in source:
data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
print >>f, "%s = %s" % (src, repr(data))
f.close()
# Generate the __init__.py file for m5.objects
def makeObjectsInitFile(self, target, source, env):
f = file(str(target[0]), 'w')
print >>f, 'from params import *'
print >>f, 'from m5.SimObject import *'
for module in source:
print >>f, 'from %s import *' % module.get_contents()
f.close()
def createSwigParam(self, target, source, env):
assert len(target) == 1 and len(source) == 1
i_file = file(target[0].abspath, 'w')
name = str(source[0].get_contents())
param = self.params[name]
for line in param.swig_decl():
print >>i_file, line
def createEnumStrings(self, target, source, env):
assert len(target) == 1 and len(source) == 1
cc_file = file(target[0].abspath, 'w')
name = str(source[0].get_contents())
obj = self.enums[name]
print >>cc_file, obj.cxx_def()
cc_file.close()
def createEnumParam(self, target, source, env):
assert len(target) == 1 and len(source) == 1
hh_file = file(target[0].abspath, 'w')
name = str(source[0].get_contents())
obj = self.enums[name]
print >>hh_file, obj.cxx_decl()
def buildParams(self, target, source, env):
names = [ s.get_contents() for s in source ]
objs = [ self.sim_objects[name] for name in names ]
out = file(target[0].abspath, 'w')
ordered_objs = []
obj_seen = set()
def order_obj(obj):
name = str(obj)
if name in obj_seen:
return
obj_seen.add(name)
if str(obj) != 'SimObject':
order_obj(obj.__bases__[0])
ordered_objs.append(obj)
for obj in objs:
order_obj(obj)
enums = set()
predecls = []
pd_seen = set()
def add_pds(*pds):
for pd in pds:
if pd not in pd_seen:
predecls.append(pd)
pd_seen.add(pd)
for obj in ordered_objs:
params = obj._params.local.values()
for param in params:
ptype = param.ptype
if issubclass(ptype, self.m5.params.Enum):
if ptype not in enums:
enums.add(ptype)
pds = param.swig_predecls()
if isinstance(pds, (list, tuple)):
add_pds(*pds)
else:
add_pds(pds)
print >>out, '%module params'
print >>out, '%{'
for obj in ordered_objs:
print >>out, '#include "params/%s.hh"' % obj
print >>out, '%}'
for pd in predecls:
print >>out, pd
enums = list(enums)
enums.sort()
for enum in enums:
print >>out, '%%include "enums/%s.hh"' % enum.__name__
print >>out
for obj in ordered_objs:
if obj.swig_objdecls:
for decl in obj.swig_objdecls:
print >>out, decl
continue
code = ''
base = obj.get_base()
code += '// stop swig from creating/wrapping default ctor/dtor\n'
code += '%%nodefault %s;\n' % obj.cxx_class
code += 'class %s ' % obj.cxx_class
if base:
code += ': public %s' % base
code += ' {};\n'
klass = obj.cxx_class;
if hasattr(obj, 'cxx_namespace'):
new_code = 'namespace %s {\n' % obj.cxx_namespace
new_code += code
new_code += '}\n'
code = new_code
klass = '%s::%s' % (obj.cxx_namespace, klass)
print >>out, code
for obj in ordered_objs:
print >>out, '%%include "params/%s.hh"' % obj
def makeSwigInit(self, target, source, env):
f = file(str(target[0]), 'w')
print >>f, 'extern "C" {'
for module in source:
print >>f, ' void init_%s();' % module.get_contents()
print >>f, '}'
print >>f, 'void init_swig() {'
for module in source:
print >>f, ' init_%s();' % module.get_contents()
print >>f, '}'
f.close()
def compilePyFile(self, target, source, env):
'''Action function to compile a .py into a .pyc'''
py_compile.compile(str(source[0]), str(target[0]))
def buildPyZip(self, target, source, env):
'''Action function to build the zip archive. Uses the
PyZipFile module included in the standard Python library.'''
py_compiled = {}
for s in self.py_sources:
compname = str(s.compiled)
assert compname not in py_compiled
py_compiled[compname] = s
zf = zipfile.ZipFile(str(target[0]), 'w')
for s in source:
zipname = str(s)
arcname = py_compiled[zipname].arcname
zf.write(zipname, arcname)
zf.close()
def traceFlagsPy(self, target, source, env):
assert(len(target) == 1)
f = file(str(target[0]), 'w')
allFlags = []
for s in source:
val = eval(s.get_contents())
allFlags.append(val)
print >>f, 'baseFlags = ['
for flag, compound, desc in allFlags:
if not compound:
print >>f, " '%s'," % flag
print >>f, " ]"
print >>f
print >>f, 'compoundFlags = ['
print >>f, " 'All',"
for flag, compound, desc in allFlags:
if compound:
print >>f, " '%s'," % flag
print >>f, " ]"
print >>f
print >>f, "allFlags = frozenset(baseFlags + compoundFlags)"
print >>f
print >>f, 'compoundFlagMap = {'
all = tuple([flag for flag,compound,desc in allFlags if not compound])
print >>f, " 'All' : %s," % (all, )
for flag, compound, desc in allFlags:
if compound:
print >>f, " '%s' : %s," % (flag, compound)
print >>f, " }"
print >>f
print >>f, 'flagDescriptions = {'
print >>f, " 'All' : 'All flags',"
for flag, compound, desc in allFlags:
print >>f, " '%s' : '%s'," % (flag, desc)
print >>f, " }"
f.close()
def traceFlagsCC(self, target, source, env):
assert(len(target) == 1)
f = file(str(target[0]), 'w')
allFlags = []
for s in source:
val = eval(s.get_contents())
allFlags.append(val)
# file header
print >>f, '''
/*
* DO NOT EDIT THIS FILE! Automatically generated
*/
#include "base/traceflags.hh"
using namespace Trace;
const char *Trace::flagStrings[] =
{'''
# The string array is used by SimpleEnumParam to map the strings
# provided by the user to enum values.
for flag, compound, desc in allFlags:
if not compound:
print >>f, ' "%s",' % flag
print >>f, ' "All",'
for flag, compound, desc in allFlags:
if compound:
print >>f, ' "%s",' % flag
print >>f, '};'
print >>f
print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
print >>f
#
# Now define the individual compound flag arrays. There is an array
# for each compound flag listing the component base flags.
#
all = tuple([flag for flag,compound,desc in allFlags if not compound])
print >>f, 'static const Flags AllMap[] = {'
for flag, compound, desc in allFlags:
if not compound:
print >>f, " %s," % flag
print >>f, '};'
print >>f
for flag, compound, desc in allFlags:
if not compound:
continue
print >>f, 'static const Flags %sMap[] = {' % flag
for flag in compound:
print >>f, " %s," % flag
print >>f, " (Flags)-1"
print >>f, '};'
print >>f
#
# Finally the compoundFlags[] array maps the compound flags
# to their individual arrays/
#
print >>f, 'const Flags *Trace::compoundFlags[] ='
print >>f, '{'
print >>f, ' AllMap,'
for flag, compound, desc in allFlags:
if compound:
print >>f, ' %sMap,' % flag
# file trailer
print >>f, '};'
f.close()
def traceFlagsHH(self, target, source, env):
assert(len(target) == 1)
f = file(str(target[0]), 'w')
allFlags = []
for s in source:
val = eval(s.get_contents())
allFlags.append(val)
# file header boilerplate
print >>f, '''
/*
* DO NOT EDIT THIS FILE!
*
* Automatically generated from traceflags.py
*/
#ifndef __BASE_TRACE_FLAGS_HH__
#define __BASE_TRACE_FLAGS_HH__
namespace Trace {
enum Flags {'''
# Generate the enum. Base flags come first, then compound flags.
idx = 0
for flag, compound, desc in allFlags:
if not compound:
print >>f, ' %s = %d,' % (flag, idx)
idx += 1
numBaseFlags = idx
print >>f, ' NumFlags = %d,' % idx
# put a comment in here to separate base from compound flags
print >>f, '''
// The remaining enum values are *not* valid indices for Trace::flags.
// They are "compound" flags, which correspond to sets of base
// flags, and are used by changeFlag.'''
print >>f, ' All = %d,' % idx
idx += 1
for flag, compound, desc in allFlags:
if compound:
print >>f, ' %s = %d,' % (flag, idx)
idx += 1
numCompoundFlags = idx - numBaseFlags
print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
# trailer boilerplate
print >>f, '''\
}; // enum Flags
// Array of strings for SimpleEnumParam
extern const char *flagStrings[];
extern const int numFlagStrings;
// Array of arraay pointers: for each compound flag, gives the list of
// base flags to set. Inidividual flag arrays are terminated by -1.
extern const Flags *compoundFlags[];
/* namespace Trace */ }
#endif // __BASE_TRACE_FLAGS_HH__
'''
f.close()