From 153130e5586e18025f7a0f05242ead3a7e2be881 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 23 Mar 2005 13:25:48 -0500 Subject: First step in fixing up parameter handling. Clean up the way ranges work, more fully support metric prefixes for all integer types, and convert memory sized parameters to the MemorySize type. python/m5/config.py: - no more _Param and _ParamProxy stuff. Use the names ParamBase and ParamFactory to hopefully make it clearer what we intend. - Get rid of RangeSize and the old Range class and more fully flesh out the Range class to deal with types of parameters and different kinds of ranges. - Call toInteger on the CheckedInt types so we can use metric prefixes in strings for all integers. - Get rid of the K, M, and G constants. Use the proper type or call one of the functions in the convert package. python/m5/convert.py: Simple way to deal with both floating point and integer strings. python/m5/objects/BaseCache.mpy: python/m5/objects/Ethernet.mpy: This is a MemorySize typed parameter --HG-- extra : convert_revision : 92b4ea662d723abdd6c0a49065b79c25400fac9b --- python/m5/config.py | 187 +++++++++++++++++++++++++--------------- python/m5/convert.py | 2 +- python/m5/objects/BaseCache.mpy | 2 +- python/m5/objects/Ethernet.mpy | 4 +- 4 files changed, 123 insertions(+), 72 deletions(-) (limited to 'python/m5') diff --git a/python/m5/config.py b/python/m5/config.py index f696adc79..3fc90f6bc 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -65,7 +65,7 @@ class Singleton(type): # object, either using keyword assignment in the constructor or in # separate assignment statements. For example: # -# cache = BaseCache('my_cache', root, size=64*K) +# cache = BaseCache('my_cache', root, size='64KB') # cache.hit_latency = 3 # cache.assoc = 8 # @@ -373,7 +373,7 @@ classes. You're trying to derive from: # now process remaining _init_dict items for key,val in cls._init_dict.items(): # param descriptions - if isinstance(val, _Param): + if isinstance(val, ParamBase): cls._new_param(key, val) # init-time-only keywords @@ -433,8 +433,8 @@ classes. You're trying to derive from: try: param.valid(value) except Exception, e: - panic("Exception: %s\nError setting param %s.%s to %s\n" % \ - (e, cls.__name__, attr, value)) + raise e.__class__, "%s\nError setting param %s.%s to %s\n" % \ + (e, cls.__name__, attr, value) cls._values[attr] = value elif isConfigNode(value) or isSimObjSequence(value): cls._values[attr] = value @@ -837,7 +837,7 @@ class Value(object): return len(self._getattr()) # Regular parameter. -class _Param(object): +class ParamBase(object): def __init__(self, ptype, *args, **kwargs): if isinstance(ptype, types.StringType): self.ptype_string = ptype @@ -909,13 +909,13 @@ class _Param(object): def cpp_decl(self, name): return '%s %s;' % (self.ptype._cpp_param_decl, name) -class _ParamProxy(object): +class ParamFactory(object): def __init__(self, type): self.ptype = type # E.g., Param.Int(5, "number of widgets") def __call__(self, *args, **kwargs): - return _Param(self.ptype, *args, **kwargs) + return ParamBase(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 @@ -929,17 +929,17 @@ class _ParamProxy(object): if attr != 'ptype': raise AttributeError, \ 'Attribute %s not available in %s' % (attr, self.__class__) - super(_ParamProxy, self).__setattr__(attr, value) + super(ParamFactory, self).__setattr__(attr, value) -Param = _ParamProxy(None) +Param = ParamFactory(None) # Vector-valued parameter description. Just like Param, except that # the value is a vector (list) of the specified type instead of a # single value. -class _VectorParam(_Param): +class VectorParamBase(ParamBase): def __init__(self, type, *args, **kwargs): - _Param.__init__(self, type, *args, **kwargs) + ParamBase.__init__(self, type, *args, **kwargs) def valid(self, value): if value == None: @@ -974,12 +974,12 @@ class _VectorParam(_Param): def cpp_decl(self, name): return 'std::vector<%s> %s;' % (self.ptype._cpp_param_decl, name) -class _VectorParamProxy(_ParamProxy): +class VectorParamFactory(ParamFactory): # E.g., VectorParam.Int(5, "number of widgets") def __call__(self, *args, **kwargs): - return _VectorParam(self.ptype, *args, **kwargs) + return VectorParamBase(self.ptype, *args, **kwargs) -VectorParam = _VectorParamProxy(None) +VectorParam = VectorParamFactory(None) ##################################################################### # @@ -995,6 +995,80 @@ VectorParam = _VectorParamProxy(None) # ##################################################################### +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, Range): + raise TypeError, 'value %s is not a Pair' % value + value = cls(value) + value.first = cls.type._convert(value.first) + value.second = cls.type._convert(value.second) + return value + + def _string(cls, value): + first = int(value.first) + second = int(value.second) + if value.extend: + second += first + if not value.inclusive: + second -= 1 + return '%s:%s' % (cls.type._string(first), cls.type._string(second)) + +class Range(ParamType): + __metaclass__ = MetaRange + def __init__(self, *args, **kwargs): + if len(args) == 0: + self.first = kwargs.pop('start') + + if 'end' in kwargs: + self.second = kwargs.pop('end') + self.inclusive = True + self.extend = False + elif 'size' in kwargs: + self.second = kwargs.pop('size') + self.inclusive = False + self.extend = True + else: + raise TypeError, "Either end or size must be specified" + + elif len(args) == 1: + if kwargs: + self.first = args[0] + if 'end' in kwargs: + self.second = kwargs.pop('end') + self.inclusive = True + self.extend = False + elif 'size' in kwargs: + self.second = kwargs.pop('size') + self.inclusive = False + self.extend = True + else: + raise TypeError, "Either end or size must be specified" + elif isinstance(args[0], Range): + self.first = args[0].first + self.second = args[0].second + self.inclusive = args[0].inclusive + self.extend = args[0].extend + else: + self.first = 0 + self.second = args[0] + self.inclusive = False + self.extend = True + + elif len(args) == 2: + self.first, self.second = args + self.inclusive = True + self.extend = False + else: + raise TypeError, "Too many arguments specified" + + if kwargs: + raise TypeError, "too many keywords: %s" % kwargs.keys() # Metaclass for bounds-checked integer parameters. See CheckedInt. class CheckedIntType(type): @@ -1028,8 +1102,10 @@ class CheckedIntType(type): if not isinstance(value, (int, long, float, str)): raise TypeError, 'Integer param of invalid type %s' % type(value) - if isinstance(value, (str, float)): - value = long(float(value)) + if isinstance(value, float): + value = long(value) + elif isinstance(value, str): + value = toInteger(value) if not cls.min <= value <= cls.max: raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ @@ -1044,7 +1120,7 @@ class CheckedIntType(type): # 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): +class CheckedInt(long,ParamType): __metaclass__ = CheckedIntType class Int(CheckedInt): cppname = 'int'; size = 32; unsigned = False @@ -1060,68 +1136,47 @@ class Int64(CheckedInt): cppname = 'int64_t'; size = 64; unsigned = False class UInt64(CheckedInt): cppname = 'uint64_t'; size = 64; unsigned = 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 class Percent(CheckedInt): cppname = 'int'; min = 0; max = 100 -class Pair(object): - def __init__(self, first, second): - self.first = first - self.second = second - -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 +class MemorySize(CheckedInt): + cppname = 'uint64_t' + size = 64 + unsigned = True + def __new__(cls, value): + return super(MemorySize, cls).__new__(cls, toMemorySize(value)) 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)) + return cls(value) + _convert = classmethod(_convert) def _string(cls, value): - return '%s:%s' % (cls.type._string(value.first), - cls.type._string(value.second)) - -class Range(ParamType): - __metaclass__ = MetaRange + return '%d' % value + _string = classmethod(_string) -def RangeSize(start, size): - return Pair(start, start + size - 1) +class Addr(MemorySize): + pass -class AddrRange(Range): type = Addr +class AddrRange(Range): + type = Addr # Boolean parameter type. class Bool(ParamType): _cpp_param_decl = 'bool' - def _convert(value): - t = type(value) - if t == bool: - return value + #def __new__(cls, value): + # return super(MemorySize, cls).__new__(cls, toBool(value)) - if t == int or t == long: - return bool(value) - - if t == str: - v = value.lower() - if v == "true" or v == "t" or v == "yes" or v == "y": - return True - elif v == "false" or v == "f" or v == "no" or v == "n": - return False - - raise TypeError, 'Bool parameter (%s) of invalid type %s' % (v, t) - _convert = staticmethod(_convert) + def _convert(cls, value): + return toBool(value) + _convert = classmethod(_convert) - def _string(value): + def _string(cls, value): if value: return "true" else: return "false" - _string = staticmethod(_string) + _string = classmethod(_string) # String-valued parameter. class String(ParamType): @@ -1291,13 +1346,9 @@ class Enum(ParamType): # # Some memory range specifications use this as a default upper bound. -MAX_ADDR = Addr.max +MaxAddr = Addr.max MaxTick = Tick.max - -# For power-of-two sizing, e.g. 64*K gives an integer value 65536. -K = 1024 -M = K*K -G = K*M +AllMemory = AddrRange(0, MaxAddr) ##################################################################### @@ -1337,6 +1388,6 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', 'Counter', 'Addr', 'Tick', 'Percent', - 'Pair', 'RangeSize', 'AddrRange', 'MAX_ADDR', 'NULL', 'K', 'M', - 'NextEthernetAddr', - 'instantiate'] + 'MemorySize', + 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL', + 'NextEthernetAddr', 'instantiate'] diff --git a/python/m5/convert.py b/python/m5/convert.py index 2ebe93889..2f69645b9 100644 --- a/python/m5/convert.py +++ b/python/m5/convert.py @@ -60,7 +60,7 @@ def toInteger(value): elif value.endswith('f'): result = int(value[:-1]) * femto else: - result = int(value) + result = int(float(value)) return result diff --git a/python/m5/objects/BaseCache.mpy b/python/m5/objects/BaseCache.mpy index 98a422e30..b9986917f 100644 --- a/python/m5/objects/BaseCache.mpy +++ b/python/m5/objects/BaseCache.mpy @@ -23,7 +23,7 @@ simobj BaseCache(BaseMem): "always service demand misses first") protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use") repl = Param.Repl(NULL, "replacement policy") - size = Param.Int("capacity in bytes") + size = Param.MemorySize("capacity in bytes") split = Param.Bool(False, "whether or not this cache is split") split_size = Param.Int(0, "How many ways of the cache belong to CPU/LRU partition") diff --git a/python/m5/objects/Ethernet.mpy b/python/m5/objects/Ethernet.mpy index cd251f36d..3acd8d04d 100644 --- a/python/m5/objects/Ethernet.mpy +++ b/python/m5/objects/Ethernet.mpy @@ -68,8 +68,8 @@ simobj NSGigE(PciDevice): rx_delay = Param.Tick(1000, "Receive Delay") tx_delay = Param.Tick(1000, "Transmit Delay") - rx_fifo_size = Param.Int(131072, "max size in bytes of rxFifo") - tx_fifo_size = Param.Int(131072, "max size in bytes of txFifo") + rx_fifo_size = Param.MemorySize('128kB', "max size in bytes of rxFifo") + tx_fifo_size = Param.MemorySize('128kB', "max size in bytes of txFifo") intr_delay = Param.Tick(0, "Interrupt Delay in microseconds") payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") -- cgit v1.2.3 From 257be7434193c8a06e024f5fa9eca151025bda1e Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 23 Mar 2005 22:58:47 -0500 Subject: Formatting fixes --HG-- extra : convert_revision : 9a726945b7a1decbecf460df6714257b88742dc8 --- python/m5/config.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'python/m5') diff --git a/python/m5/config.py b/python/m5/config.py index 3fc90f6bc..e097173f3 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -740,8 +740,6 @@ class Node(object): # print type and parameter values to .ini file def outputDot(self, dot): - - label = "{%s|" % self.path if isSimObject(self.realtype): label += '%s|' % self.type @@ -931,7 +929,6 @@ class ParamFactory(object): 'Attribute %s not available in %s' % (attr, self.__class__) super(ParamFactory, self).__setattr__(attr, value) - Param = ParamFactory(None) # Vector-valued parameter description. Just like Param, except that @@ -1198,7 +1195,6 @@ class String(ParamType): return value _string = classmethod(_string) - def IncEthernetAddr(addr, val = 1): bytes = map(lambda x: int(x, 16), addr.split(':')) bytes[5] += val @@ -1294,7 +1290,6 @@ Null = NULL = NullSimObject() # Metaclass for Enum types class MetaEnum(type): - def __init__(cls, name, bases, init_dict): if init_dict.has_key('map'): if not isinstance(cls.map, dict): -- cgit v1.2.3 From eeff53841a6cb6c3819b69543fae861fa84cc541 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 24 Mar 2005 12:24:17 -0500 Subject: Add Frequency and Latency as new parameter types and use them where we can python/m5/config.py: Add two new parameter types: Frequency and Latency. These will soon be an integral part of the tick is picosecond thing. If the value can be converted directly to an integer without any special tricks, we assume that the number is the exact value desired. Otherwise, we convert the number assuming that it is in Hz or s. python/m5/objects/Bus.mpy: Use the new Latency and Frequency types where we can --HG-- extra : convert_revision : b3cff6020db83fb819507c348451c98697d1cf27 --- python/m5/config.py | 40 ++++++++++++++++++++++++++++++++++++++-- python/m5/objects/Bus.mpy | 2 +- 2 files changed, 39 insertions(+), 3 deletions(-) (limited to 'python/m5') diff --git a/python/m5/config.py b/python/m5/config.py index e097173f3..1af2c5e3e 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -27,7 +27,7 @@ from __future__ import generators import os, re, sys, types, inspect -from m5 import panic +from m5 import panic, env from convert import * from multidict import multidict @@ -1340,6 +1340,42 @@ class Enum(ParamType): # "Constants"... handy aliases for various values. # +class Frequency(int,ParamType): + _cpp_param_decl = 'Tick' + + def __new__(cls, value): + if isinstance(value, basestring): + val = int(env['FREQUENCY'] / toFrequency(value)) + else: + val = toFrequency(value) + return super(cls, Frequency).__new__(cls, val) + + def _convert(cls, value): + return cls(value) + _convert = classmethod(_convert) + + def _string(cls, value): + return '%d' % value + _string = classmethod(_string) + +class Latency(int,ParamType): + _cpp_param_decl = 'Tick' + def __new__(cls, value): + if isinstance(value, basestring): + val = int(env['FREQUENCY'] * toLatency(value)) + else: + val = toLatency(value) + return super(cls, Latency).__new__(cls, val) + + def _convert(cls, value): + return cls(value) + _convert = classmethod(_convert) + + def _string(cls, value): + return '%d' % value + _string = classmethod(_string) + + # Some memory range specifications use this as a default upper bound. MaxAddr = Addr.max MaxTick = Tick.max @@ -1383,6 +1419,6 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', 'Counter', 'Addr', 'Tick', 'Percent', - 'MemorySize', + 'MemorySize', 'Frequency', 'Latency', 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL', 'NextEthernetAddr', 'instantiate'] diff --git a/python/m5/objects/Bus.mpy b/python/m5/objects/Bus.mpy index 025d69785..330a2c82b 100644 --- a/python/m5/objects/Bus.mpy +++ b/python/m5/objects/Bus.mpy @@ -2,5 +2,5 @@ from BaseHier import BaseHier simobj Bus(BaseHier): type = 'Bus' - clock_ratio = Param.Int("ratio of CPU to bus frequency") + clock_ratio = Param.Frequency("ratio of CPU to bus frequency") width = Param.Int("bus width in bytes") -- cgit v1.2.3 From d10412d565c8138cd4649c8ea905cd892cf2a4d2 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 24 Mar 2005 12:24:54 -0500 Subject: Improve toBool python/m5/convert.py: an empty string should still be false --HG-- extra : convert_revision : dd9900794d94cd018b57ec81bcbce1d412e2a83e --- python/m5/convert.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'python/m5') diff --git a/python/m5/convert.py b/python/m5/convert.py index 2f69645b9..4a4492af7 100644 --- a/python/m5/convert.py +++ b/python/m5/convert.py @@ -81,6 +81,8 @@ def toBool(val): return True elif val == "false" or val == "f" or val == "no" or val == "n": return False + elif val == "": + return False return toInteger(val) != 0 -- cgit v1.2.3 From 7e1995a29c25e174dda2eafc7980e0a0770133d8 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Fri, 25 Mar 2005 22:32:00 -0500 Subject: Better exceptions in python config python/m5/config.py: Don't raise a new exception, just modify and re-raise the old one. --HG-- extra : convert_revision : 47f6da3a8cb2ee18a6b400863e7ea80ab0c9a5ea --- python/m5/config.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'python/m5') diff --git a/python/m5/config.py b/python/m5/config.py index 1af2c5e3e..3b5d94b15 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -433,8 +433,10 @@ classes. You're trying to derive from: try: param.valid(value) except Exception, e: - raise e.__class__, "%s\nError setting param %s.%s to %s\n" % \ + msg = "%s\nError setting param %s.%s to %s\n" % \ (e, cls.__name__, attr, value) + e.args = (msg, ) + raise cls._values[attr] = value elif isConfigNode(value) or isSimObjSequence(value): cls._values[attr] = value @@ -510,8 +512,10 @@ classes. You're trying to derive from: instance.params.append(p) instance.param_names[pname] = p except Exception, e: - raise e.__class__, 'Exception while evaluating %s.%s\n%s' % \ + msg = 'Exception while evaluating %s.%s\n%s' % \ (instance.path, pname, e) + e.args = (msg, ) + raise return instance @@ -693,8 +697,10 @@ class Node(object): else: param.value = self.unproxy(pval, ptype) except Exception, e: - raise e.__class__, 'Error while fixing up %s:%s\n%s' % \ + msg = 'Error while fixing up %s:%s\n%s' % \ (self.path, param.name, e) + e.args = (msg, ) + raise for child in self.children: assert(child != self) @@ -727,8 +733,9 @@ class Node(object): value = param.convert(param.value) string = param.string(value) except Exception, e: - raise e.__class__, 'exception in %s:%s\n%s' % \ - (self.path, param.name, e) + msg = 'exception in %s:%s\n%s' % (self.path, param.name, e) + e.args = (msg, ) + raise print '%s = %s' % (param.name, string) @@ -760,9 +767,10 @@ class Node(object): value = param.convert(param.value) string = param.string(value) except Exception, e: - raise e.__class__, 'exception in %s:%s\n%s' % \ - (self.name, param.name, e) + msg = 'exception in %s:%s\n%s' % (self.name, param.name, e) + e.args = (msg, ) raise + if isConfigNode(param.ptype) and string != "Null": simobjs.append(string) else: -- cgit v1.2.3 From 40bab977bc09d6126177ee34c51076ee1fff37f7 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Fri, 25 Mar 2005 22:59:29 -0500 Subject: Better handling of latency/frequency parameter types python/m5/config.py: Addr is slightly different from memory size in that Addr will take non strings. Deal with the fact that the convert.toFoo functions only accept strings. Add RootFrequency as a special type for the Root.frequency parameter which is not scaled. Add ClockPeriod parameter type. python/m5/convert.py: Be more strict about what's allowed. Only accept strings as inputs for these conversion functions. If the user wants to accept something else, they need to deal with the failure and convert other types on their own. python/m5/objects/Bus.mpy: Use the new ClockPeriod parameter type python/m5/objects/Root.mpy: Can't use integers for frequency anymore python/m5/smartdict.py: rename SmartDict.Proxy to just Variable. Create a new class UndefinedVariable that is returned when the user tries to get a variable that is not in the dict. Undefined variable evaluates to false, and will cause an error elsewhere. --HG-- extra : convert_revision : 1d55246fd1af65106f102396234827d6401ef9ce --- python/m5/config.py | 125 +++++++++++++++++++++++---- python/m5/convert.py | 205 +++++++++++++++++++++++++-------------------- python/m5/objects/Bus.mpy | 2 +- python/m5/objects/Root.mpy | 2 +- python/m5/smartdict.py | 156 +++++++++++++++++++--------------- 5 files changed, 310 insertions(+), 180 deletions(-) (limited to 'python/m5') diff --git a/python/m5/config.py b/python/m5/config.py index 3b5d94b15..a791bbebf 100644 --- a/python/m5/config.py +++ b/python/m5/config.py @@ -1160,8 +1160,24 @@ class MemorySize(CheckedInt): return '%d' % value _string = classmethod(_string) -class Addr(MemorySize): - pass +class Addr(CheckedInt): + cppname = 'Addr' + size = 64 + unsigned = True + def __new__(cls, value): + try: + value = long(toMemorySize(value)) + except TypeError: + value = long(value) + return super(Addr, cls).__new__(cls, value) + + def _convert(cls, value): + return cls(value) + _convert = classmethod(_convert) + + def _string(cls, value): + return '%d' % value + _string = classmethod(_string) class AddrRange(Range): type = Addr @@ -1169,15 +1185,18 @@ class AddrRange(Range): # Boolean parameter type. class Bool(ParamType): _cpp_param_decl = 'bool' - #def __new__(cls, value): - # return super(MemorySize, cls).__new__(cls, toBool(value)) + def __init__(self, value): + try: + self.value = toBool(value) + except TypeError: + self.value = bool(value) def _convert(cls, value): - return toBool(value) + return cls(value) _convert = classmethod(_convert) def _string(cls, value): - if value: + if value.value: return "true" else: return "false" @@ -1344,42 +1363,109 @@ class Enum(ParamType): def _string(self, value): return str(value) _string = classmethod(_string) + +root_frequency = None + # # "Constants"... handy aliases for various values. # +class RootFrequency(float,ParamType): + _cpp_param_decl = 'Tick' -class Frequency(int,ParamType): + def __new__(cls, value): + return super(cls, RootFrequency).__new__(cls, toFrequency(value)) + + def _convert(cls, value): + return cls(value) + _convert = classmethod(_convert) + + def _string(cls, value): + return '%d' % int(value) + _string = classmethod(_string) + +class ClockPeriod(float,ParamType): + _cpp_param_decl = 'Tick' + def __new__(cls, value): + relative = False + try: + val = toClockPeriod(value) + except ValueError, e: + relative = True + if value.endswith('f'): + val = float(value[:-1]) + if val: + val = 1 / val + elif value.endswith('c'): + val = float(value[:-1]) + else: + raise e + + self = super(cls, ClockPeriod).__new__(cls, val) + self.relative = relative + return self + + def _convert(cls, value): + return cls(value) + _convert = classmethod(_convert) + + def _string(cls, value): + if not value.relative: + value *= root_frequency + + return '%d' % int(value) + _string = classmethod(_string) + +class Frequency(float,ParamType): _cpp_param_decl = 'Tick' def __new__(cls, value): - if isinstance(value, basestring): - val = int(env['FREQUENCY'] / toFrequency(value)) - else: + relative = False + try: val = toFrequency(value) - return super(cls, Frequency).__new__(cls, val) + except ValueError, e: + if value.endswith('f'): + val = float(value[:-1]) + relative = True + else: + raise e + self = super(cls, Frequency).__new__(cls, val) + self.relative = relative + return self def _convert(cls, value): return cls(value) _convert = classmethod(_convert) def _string(cls, value): - return '%d' % value + if not value.relative: + value = root_frequency / value + + return '%d' % int(value) _string = classmethod(_string) -class Latency(int,ParamType): +class Latency(float,ParamType): _cpp_param_decl = 'Tick' def __new__(cls, value): - if isinstance(value, basestring): - val = int(env['FREQUENCY'] * toLatency(value)) - else: + relative = False + try: val = toLatency(value) - return super(cls, Latency).__new__(cls, val) + except ValueError, e: + if value.endswith('c'): + val = float(value[:-1]) + relative = True + else: + raise e + self = super(cls, Latency).__new__(cls, val) + self.relative = relative + return self def _convert(cls, value): return cls(value) _convert = classmethod(_convert) def _string(cls, value): + if not value.relative: + value *= root_frequency return '%d' % value _string = classmethod(_string) @@ -1394,7 +1480,9 @@ AllMemory = AddrRange(0, MaxAddr) # The final hook to generate .ini files. Called from configuration # script once config is built. def instantiate(root): + global root_frequency instance = root.instantiate('root') + root_frequency = RootFrequency._convert(root.frequency._getattr()) instance.fixup() instance.display() if not noDot: @@ -1427,6 +1515,7 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', 'Counter', 'Addr', 'Tick', 'Percent', - 'MemorySize', 'Frequency', 'Latency', + 'MemorySize', 'RootFrequency', 'Frequency', 'Latency', + 'ClockPeriod', 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL', 'NextEthernetAddr', 'instantiate'] diff --git a/python/m5/convert.py b/python/m5/convert.py index 4a4492af7..6ccefd2fc 100644 --- a/python/m5/convert.py +++ b/python/m5/convert.py @@ -22,162 +22,185 @@ pebi = tebi * 1024 exbi = pebi * 1024 # memory size configuration stuff -def toInteger(value): +def toFloat(value): if not isinstance(value, str): - result = int(value) - elif value.endswith('Ei'): - result = int(value[:-2]) * exbi + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Ei'): + return float(value[:-2]) * exbi elif value.endswith('Pi'): - result = int(value[:-2]) * pebi + return float(value[:-2]) * pebi elif value.endswith('Ti'): - result = int(value[:-2]) * tebi + return float(value[:-2]) * tebi elif value.endswith('Gi'): - result = int(value[:-2]) * gibi + return float(value[:-2]) * gibi elif value.endswith('Mi'): - result = int(value[:-2]) * mebi + return float(value[:-2]) * mebi elif value.endswith('ki'): - result = int(value[:-2]) * kibi + return float(value[:-2]) * kibi elif value.endswith('E'): - result = int(value[:-1]) * exa + return float(value[:-1]) * exa elif value.endswith('P'): - result = int(value[:-1]) * peta + return float(value[:-1]) * peta elif value.endswith('T'): - result = int(value[:-1]) * tera + return float(value[:-1]) * tera elif value.endswith('G'): - result = int(value[:-1]) * giga + return float(value[:-1]) * giga elif value.endswith('M'): - result = int(value[:-1]) * mega + return float(value[:-1]) * mega elif value.endswith('k'): - result = int(value[:-1]) * kilo + return float(value[:-1]) * kilo elif value.endswith('m'): - result = int(value[:-1]) * milli + return float(value[:-1]) * milli elif value.endswith('u'): - result = int(value[:-1]) * micro + return float(value[:-1]) * micro elif value.endswith('n'): - result = int(value[:-1]) * nano + return float(value[:-1]) * nano elif value.endswith('p'): - result = int(value[:-1]) * pico + return float(value[:-1]) * pico elif value.endswith('f'): - result = int(value[:-1]) * femto + return float(value[:-1]) * femto else: - result = int(float(value)) + return float(value) + +def toLong(value): + value = toFloat(value) + result = int(value) + if value != result: + raise ValueError, "cannot convert '%s' to long" % value return result -def toBool(val): - t = type(val) - if t == bool: - return val +def toInteger(value): + value = toFloat(value) + result = int(value) + if value != result: + raise ValueError, "cannot convert '%s' to integer" % value - if t == None: - return False + return result - if t == int or t == long: - return bool(val) +def toBool(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) - if t == str: - val = val.lower() - if val == "true" or val == "t" or val == "yes" or val == "y": - return True - elif val == "false" or val == "f" or val == "no" or val == "n": - return False - elif val == "": - return False + value = value.lower() + if value == "true" or value == "t" or value == "yes" or value == "y": + return True + elif value == "false" or value == "f" or value == "no" or value == "n": + return False - return toInteger(val) != 0 + raise ValueError, "cannot convert '%s' to bool" % value def toFrequency(value): if not isinstance(value, str): - result = float(value) - elif value.endswith('THz'): - result = float(value[:-3]) * tera + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('THz'): + return float(value[:-3]) * tera elif value.endswith('GHz'): - result = float(value[:-3]) * giga + return float(value[:-3]) * giga elif value.endswith('MHz'): - result = float(value[:-3]) * mega + return float(value[:-3]) * mega elif value.endswith('kHz'): - result = float(value[:-3]) * kilo + return float(value[:-3]) * kilo elif value.endswith('Hz'): - result = float(value[:-2]) - else: - result = float(value) + return float(value[:-2]) - return result + raise ValueError, "cannot convert '%s' to frequency" % value def toLatency(value): if not isinstance(value, str): - result = float(value) - elif value.endswith('c'): - result = float(value[:-1]) - elif value.endswith('ps'): - result = float(value[:-2]) * pico + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('ps'): + return float(value[:-2]) * pico elif value.endswith('ns'): - result = float(value[:-2]) * nano + return float(value[:-2]) * nano elif value.endswith('us'): - result = float(value[:-2]) * micro + return float(value[:-2]) * micro elif value.endswith('ms'): - result = float(value[:-2]) * milli + return float(value[:-2]) * milli elif value.endswith('s'): - result = float(value[:-1]) - else: - result = float(value) + return float(value[:-1]) + + raise ValueError, "cannot convert '%s' to latency" % value + +def toClockPeriod(value): + """result is a clock period""" + + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + try: + val = toFrequency(value) + if val != 0: + val = 1 / val + return val + except ValueError: + pass + + try: + val = toLatency(value) + return val + except ValueError: + pass + + raise ValueError, "cannot convert '%s' to clock period" % value - return result; def toNetworkBandwidth(value): if not isinstance(value, str): - result = float(value) - elif value.endswith('Tbps'): - result = float(value[:-3]) * tera + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Tbps'): + return float(value[:-3]) * tera elif value.endswith('Gbps'): - result = float(value[:-3]) * giga + return float(value[:-3]) * giga elif value.endswith('Mbps'): - result = float(value[:-3]) * mega + return float(value[:-3]) * mega elif value.endswith('kbps'): - result = float(value[:-3]) * kilo + return float(value[:-3]) * kilo elif value.endswith('bps'): - result = float(value[:-2]) + return float(value[:-2]) else: - result = float(value) + return float(value) - return result + raise ValueError, "cannot convert '%s' to network bandwidth" % value def toMemoryBandwidth(value): if not isinstance(value, str): - result = int(value) - elif value.endswith('PB/s'): - result = int(value[:-4]) * pebi + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('PB/s'): + return float(value[:-4]) * pebi elif value.endswith('TB/s'): - result = int(value[:-4]) * tebi + return float(value[:-4]) * tebi elif value.endswith('GB/s'): - result = int(value[:-4]) * gibi + return float(value[:-4]) * gibi elif value.endswith('MB/s'): - result = int(value[:-4]) * mebi + return float(value[:-4]) * mebi elif value.endswith('kB/s'): - result = int(value[:-4]) * kibi + return float(value[:-4]) * kibi elif value.endswith('B/s'): - result = int(value[:-3]) - else: - result = int(value) + return float(value[:-3]) - return result + raise ValueError, "cannot convert '%s' to memory bandwidth" % value def toMemorySize(value): if not isinstance(value, str): - result = int(value) - elif value.endswith('PB'): - result = int(value[:-2]) * pebi + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('PB'): + return float(value[:-2]) * pebi elif value.endswith('TB'): - result = int(value[:-2]) * tebi + return float(value[:-2]) * tebi elif value.endswith('GB'): - result = int(value[:-2]) * gibi + return float(value[:-2]) * gibi elif value.endswith('MB'): - result = int(value[:-2]) * mebi + return float(value[:-2]) * mebi elif value.endswith('kB'): - result = int(value[:-2]) * kibi + return float(value[:-2]) * kibi elif value.endswith('B'): - result = int(value[:-1]) - else: - result = int(value) + return float(value[:-1]) - return result + raise ValueError, "cannot convert '%s' to memory size" % value diff --git a/python/m5/objects/Bus.mpy b/python/m5/objects/Bus.mpy index 330a2c82b..aa12f757a 100644 --- a/python/m5/objects/Bus.mpy +++ b/python/m5/objects/Bus.mpy @@ -2,5 +2,5 @@ from BaseHier import BaseHier simobj Bus(BaseHier): type = 'Bus' - clock_ratio = Param.Frequency("ratio of CPU to bus frequency") + clock_ratio = Param.ClockPeriod("ratio of CPU to bus frequency") width = Param.Int("bus width in bytes") diff --git a/python/m5/objects/Root.mpy b/python/m5/objects/Root.mpy index 0e531054b..c535bd2dc 100644 --- a/python/m5/objects/Root.mpy +++ b/python/m5/objects/Root.mpy @@ -5,7 +5,7 @@ from Trace import Trace simobj Root(SimObject): type = 'Root' - frequency = Param.Tick(200000000, "tick frequency") + frequency = Param.RootFrequency('200MHz', "tick frequency") output_file = Param.String('cout', "file to dump simulator output to") full_system = Param.Bool("Full system simulation?") hier = HierParams(do_data = False, do_events = True) diff --git a/python/m5/smartdict.py b/python/m5/smartdict.py index 0dbcc50b0..a2661c279 100644 --- a/python/m5/smartdict.py +++ b/python/m5/smartdict.py @@ -16,93 +16,111 @@ from convert import * +class Variable(str): + """Intelligent proxy class for SmartDict. Variable will use the + various convert functions to attempt to convert values to useable + types""" + def __int__(self): + return toInteger(str(self)) + def __long__(self): + return toLong(str(self)) + def __float__(self): + return toFloat(str(self)) + def __nonzero__(self): + return toBool(str(self)) + def convert(self, other): + t = type(other) + if t == bool: + return bool(self) + if t == int: + return int(self) + if t == long: + return long(self) + if t == float: + return float(self) + return str(self) + def __lt__(self, other): + return self.convert(other) < other + def __le__(self, other): + return self.convert(other) <= other + def __eq__(self, other): + return self.convert(other) == other + def __ne__(self, other): + return self.convert(other) != other + def __gt__(self, other): + return self.convert(other) > other + def __ge__(self, other): + return self.convert(other) >= other + + def __add__(self, other): + return self.convert(other) + other + def __sub__(self, other): + return self.convert(other) - other + def __mul__(self, other): + return self.convert(other) * other + def __div__(self, other): + return self.convert(other) / other + def __truediv__(self, other): + return self.convert(other) / other + + def __radd__(self, other): + return other + self.convert(other) + def __rsub__(self, other): + return other - self.convert(other) + def __rmul__(self, other): + return other * self.convert(other) + def __rdiv__(self, other): + return other / self.convert(other) + def __rtruediv__(self, other): + return other / self.convert(other) + +class UndefinedVariable(object): + """Placeholder class to represent undefined variables. Will + generally cause an exception whenever it is used, but evaluates to + zero for boolean truth testing such as in an if statement""" + def __nonzero__(self): + return False + class SmartDict(dict): + """Dictionary class that holds strings, but intelligently converts + those strings to other types depending on their usage""" - class Proxy(str): - def __int__(self): - return int(toInteger(str(self))) - def __long__(self): - return long(toInteger(str(self))) - def __float__(self): - return float(toInteger(str(self))) - def __nonzero__(self): - return toBool(str(self)) - def convert(self, other): - t = type(other) - if t == bool: - return bool(self) - if t == int: - return int(self) - if t == long: - return long(self) - if t == float: - return float(self) - return str(self) - def __lt__(self, other): - return self.convert(other) < other - def __le__(self, other): - return self.convert(other) <= other - def __eq__(self, other): - return self.convert(other) == other - def __ne__(self, other): - return self.convert(other) != other - def __gt__(self, other): - return self.convert(other) > other - def __ge__(self, other): - return self.convert(other) >= other - - def __add__(self, other): - return self.convert(other) + other - def __sub__(self, other): - return self.convert(other) - other - def __mul__(self, other): - return self.convert(other) * other - def __div__(self, other): - return self.convert(other) / other - def __truediv__(self, other): - return self.convert(other) / other - - def __radd__(self, other): - return other + self.convert(other) - def __rsub__(self, other): - return other - self.convert(other) - def __rmul__(self, other): - return other * self.convert(other) - def __rdiv__(self, other): - return other / self.convert(other) - def __rtruediv__(self, other): - return other / self.convert(other) - - - # __getitem__ uses dict.get() to return 'False' if the key is not - # found (rather than raising KeyError). Note that this does *not* - # set the key's value to 'False' in the dict, so that even after - # we call env['foo'] we still get a meaningful answer from "'foo' - # in env" (which calls dict.__contains__, which we do not - # override). def __getitem__(self, key): - return self.Proxy(dict.get(self, key, 'False')) + """returns a Variable proxy if the values exists in the database and + returns an UndefinedVariable otherwise""" + + if key in self: + return Variable(dict.get(self, key)) + else: + # Note that this does *not* change the contents of the dict, + # so that even after we call env['foo'] we still get a + # meaningful answer from "'foo' in env" (which + # calls dict.__contains__, which we do not override). + return UndefinedVariable() def __setitem__(self, key, item): + """intercept the setting of any variable so that we always + store strings in the dict""" dict.__setitem__(self, key, str(item)) def values(self): - return [ self.Proxy(v) for v in dict.values(self) ] + return [ Variable(v) for v in dict.values(self) ] def itervalues(self): for value in dict.itervalues(self): - yield self.Proxy(value) + yield Variable(value) def items(self): - return [ (k, self.Proxy(v)) for k,v in dict.items(self) ] + return [ (k, Variable(v)) for k,v in dict.items(self) ] def iteritems(self): for key,value in dict.iteritems(self): - yield key, self.Proxy(value) + yield key, Variable(value) def get(self, key, default='False'): - return self.Proxy(dict.get(self, key, str(default))) + return Variable(dict.get(self, key, str(default))) def setdefault(self, key, default='False'): - return self.Proxy(dict.setdefault(self, key, str(default))) + return Variable(dict.setdefault(self, key, str(default))) +__all__ = [ 'SmartDict' ] -- cgit v1.2.3