X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fpython%2Fm5%2Fparams.py;h=38e320b5302dcd16aa39bd35659351c2149ffccc;hb=69fc2af00600ced942d81dba082d9780e5325c9e;hp=88b16287459f3c828760869a1395c62096cceea7;hpb=fcf85725b5d2d67458c00680948d0a7baab942d4;p=gem5.git diff --git a/src/python/m5/params.py b/src/python/m5/params.py index 88b162874..38e320b53 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -1,4 +1,5 @@ # Copyright (c) 2004-2006 The Regents of The University of Michigan +# Copyright (c) 2010 Advanced Micro Devices, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -46,18 +47,38 @@ import copy import datetime -import inspect +import re import sys import time +import math -import convert import proxy import ticks from util import * +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) + +allParams = {} + +class MetaParamValue(type): + def __new__(mcls, name, bases, dct): + cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) + assert name not in allParams + allParams[name] = cls + return cls + + # Dummy base class to identify types that are legitimate for SimObject # parameters. class ParamValue(object): + __metaclass__ = MetaParamValue cxx_predecls = [] swig_predecls = [] @@ -74,6 +95,8 @@ class ParamValue(object): # Regular parameter description. class ParamDesc(object): + file_ext = 'ptype' + def __init__(self, ptype_str, ptype, *args, **kwargs): self.ptype_str = ptype_str # remember ptype only if it is provided @@ -107,15 +130,11 @@ class ParamDesc(object): def __getattr__(self, attr): if attr == 'ptype': - try: - ptype = eval(self.ptype_str, objects.__dict__) - 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 + ptype = SimObject.allClasses[self.ptype_str] + assert isSimObjectClass(ptype) + self.ptype = ptype + return ptype + raise AttributeError, "'%s' object has no attribute '%s'" % \ (type(self).__name__, attr) @@ -147,38 +166,86 @@ class ParamDesc(object): # single value. class VectorParamValue(list): + __metaclass__ = MetaParamValue + def __setattr__(self, attr, value): + raise AttributeError, \ + "Not allowed to set %s on '%s'" % (attr, type(self).__name__) + 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] -class SimObjVector(VectorParamValue): - def print_ini(self): +class SimObjectVector(VectorParamValue): + # support clone operation + def __call__(self, **kwargs): + return SimObjectVector([v(**kwargs) for v in self]) + + def clear_parent(self, old_parent): + for v in self: + v.clear_parent(old_parent) + + def set_parent(self, parent, name): + if len(self) == 1: + self[0].set_parent(parent, name) + else: + width = int(math.ceil(math.log(len(self))/math.log(10))) + for i,v in enumerate(self): + v.set_parent(parent, "%s%0*d" % (name, width, i)) + + def get_parent(self): + parent_set = set(v._parent for v in self) + if len(parent_set) != 1: + raise RuntimeError, \ + "SimObjectVector elements have inconsistent parent value." + return parent_set.pop() + + # return 'cpu0 cpu1' etc. for print_ini() + def get_name(self): + return ' '.join([v._name for v in self]) + + # By iterating through the constituent members of the vector here + # we can nicely handle iterating over all a SimObject's children + # without having to provide lots of special functions on + # SimObjectVector directly. + def descendants(self): for v in self: - v.print_ini() + for obj in v.descendants(): + yield obj class VectorParamDesc(ParamDesc): + file_ext = 'vptype' + # Convert assigned value to appropriate type. If the RHS is not a # list or tuple, it generates a single-element list. def convert(self, value): 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 '] + self.ptype.cxx_predecls + if isSimObjectSequence(tmp_list): + return SimObjectVector(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 '] + self.ptype.cxx_predecls def cxx_decl(self): return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name) @@ -195,15 +262,10 @@ class ParamFactory(object): # E.g., Param.Int(5, "number of widgets") def __call__(self, *args, **kwargs): - caller_frame = inspect.currentframe().f_back ptype = None try: - ptype = eval(self.ptype_str, - caller_frame.f_globals, caller_frame.f_locals) - if not isinstance(ptype, type): - raise TypeError, \ - "Param qualifier is not a type: %s" % ptype - except NameError: + ptype = allParams[self.ptype_str] + except KeyError: # if name isn't defined yet, assume it's a SimObject, and # try to resolve it later pass @@ -232,7 +294,10 @@ class String(ParamValue,str): cxx_predecls = ['#include '] 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 @@ -275,7 +340,7 @@ class NumericParamValue(ParamValue): return newobj # Metaclass for bounds-checked integer parameters. See CheckedInt. -class CheckedIntType(type): +class CheckedIntType(MetaParamValue): def __init__(cls, name, bases, dict): super(CheckedIntType, cls).__init__(name, bases, dict) @@ -287,18 +352,18 @@ class CheckedIntType(type): if not cls.cxx_predecls: # most derived types require this, so we just do it here once - cls.cxx_predecls = ['#include "sim/host.hh"'] + cls.cxx_predecls = ['#include "base/types.hh"'] 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' + - '%import "sim/host.hh"'] + cls.swig_predecls = ['%import "stdint.i"\n' + + '%import "base/types.hh"'] 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); + " 'min' and 'max' or 'size' and 'unsigned'\n", + name); if cls.unsigned: cls.min = 0 cls.max = 2 ** cls.size - 1 @@ -328,6 +393,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 +418,16 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 class Float(ParamValue, float): cxx_type = 'double' + def __init__(self, value): + if isinstance(value, (int, long, float, NumericParamValue, Float)): + self.value = float(value) + else: + raise TypeError, "Can't convert object of type %s to Float" \ + % type(value).__name__ + + def getValue(self): + return float(self.value) + class MemorySize(CheckedInt): cxx_type = 'uint64_t' size = 64 @@ -374,7 +452,6 @@ class MemorySize32(CheckedInt): class Addr(CheckedInt): cxx_type = 'Addr' - cxx_predecls = ['#include "targetarch/isa_traits.hh"'] size = 64 unsigned = True def __init__(self, value): @@ -393,7 +470,7 @@ class Addr(CheckedInt): return self.value + other -class MetaRange(type): +class MetaRange(MetaParamValue): def __init__(cls, name, bases, dict): super(MetaRange, cls).__init__(name, bases, dict) if name == 'Range': @@ -425,6 +502,9 @@ class Range(ParamValue): elif isinstance(args[0], Range): self.first = self.type(args[0].first) self.second = self.type(args[0].second) + elif isinstance(args[0], (list, tuple)): + self.first = self.type(args[0][0]) + self.second = self.type(args[0][1]) else: self.first = self.type(0) self.second = self.type(args[0]) - 1 @@ -443,9 +523,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 +556,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 +590,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 +614,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 +660,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 ' ] + 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 +712,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): +class MetaEnum(MetaParamValue): + 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,7 +742,7 @@ 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) @@ -611,10 +750,33 @@ class MetaEnum(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 + name = cls.__name__ + code = "#ifndef __ENUM__%s\n" % name + code += '#define __ENUM__%s\n' % name + code += '\n' + code += 'namespace Enums {\n' + code += ' enum %s {\n' % name + for val in cls.vals: + code += ' %s = %d,\n' % (val, cls.map[val]) + code += ' Num_%s = %d,\n' % (name, len(cls.vals)) + code += ' };\n' + code += ' extern const char *%sStrings[Num_%s];\n' % (name, name) + code += '}\n' + code += '\n' + code += '#endif\n' + return code + + def cxx_def(cls): + name = cls.__name__ + code = '#include "enums/%s.hh"\n' % name + code += 'namespace Enums {\n' + code += ' const char *%sStrings[Num_%s] =\n' % (name, name) + 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 +789,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 @@ -635,9 +800,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' + - '%import "sim/host.hh"'] + cxx_predecls = ['#include "base/types.hh"'] + swig_predecls = ['%import "stdint.i"\n' + + '%import "base/types.hh"'] + + def getValue(self): + return long(self.value) class Latency(TickParamValue): def __init__(self, value): @@ -661,12 +829,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,20 +863,24 @@ 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 /). # An explicit conversion to a Latency or Frequency must be made first. class Clock(ParamValue): cxx_type = 'Tick' - cxx_predecls = ['#include "sim/host.hh"'] - swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + - '%import "sim/host.hh"'] + cxx_predecls = ['#include "base/types.hh"'] + swig_predecls = ['%import "stdint.i"\n' + + '%import "base/types.hh"'] def __init__(self, value): if isinstance(value, (Latency, Clock)): self.ticks = value.ticks @@ -726,6 +902,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,15 +918,19 @@ 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' - def __new__(self, value): + def __new__(cls, value): # we want the number of ticks per byte of data val = convert.toMemoryBandwidth(value) return super(cls, MemoryBandwidth).__new__(cls, val) @@ -755,11 +938,17 @@ 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) + value = float(self) + if value: + 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 +975,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() @@ -845,6 +1038,7 @@ class PortRef(object): if self.peer and not proxy.isproxy(self.peer): print "warning: overwriting port", self, \ "value", self.peer, "with", other + self.peer.peer = None self.peer = other if proxy.isproxy(other): other.set_param_desc(PortParamDesc()) @@ -882,11 +1076,21 @@ class PortRef(object): # Call C++ to create corresponding port connection between C++ objects def ccConnect(self): + from m5.objects.params import connectPorts + if self.ccConnected: # already done this return peer = self.peer - internal.sim_object.connectPorts(self.simobj.getCCObject(), self.name, - self.index, peer.simobj.getCCObject(), peer.name, peer.index) + if not self.peer: # nothing to connect to + return + try: + connectPorts(self.simobj.getCCObject(), self.name, self.index, + peer.simobj.getCCObject(), peer.name, peer.index) + except: + print "Error connecting port %s.%s to %s.%s" % \ + (self.simobj.path(), self.name, + peer.simobj.path(), peer.name) + raise self.ccConnected = True peer.ccConnected = True @@ -1006,6 +1210,14 @@ class PortParamDesc(object): ptype_str = 'Port' ptype = Port +baseEnums = allEnums.copy() +baseParams = allParams.copy() + +def clear(): + global allEnums, allParams + + allEnums = baseEnums.copy() + allParams = baseParams.copy() __all__ = ['Param', 'VectorParam', 'Enum', 'Bool', 'String', 'Float', @@ -1022,7 +1234,4 @@ __all__ = ['Param', 'VectorParam', 'NextEthernetAddr', 'NULL', 'Port', 'VectorPort'] -# see comment on imports at end of __init__.py. -from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass -import objects -import internal +import SimObject