1# Copyright (c) 2012 ARM Limited 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Copyright (c) 2004-2006 The Regents of The University of Michigan 14# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 15# All rights reserved. 16# 17# Redistribution and use in source and binary forms, with or without 18# modification, are permitted provided that the following conditions are 19# met: redistributions of source code must retain the above copyright 20# notice, this list of conditions and the following disclaimer; 21# redistributions in binary form must reproduce the above copyright 22# notice, this list of conditions and the following disclaimer in the 23# documentation and/or other materials provided with the distribution; 24# neither the name of the copyright holders nor the names of its 25# contributors may be used to endorse or promote products derived from 26# this software without specific prior written permission. 27# 28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39# 40# Authors: Steve Reinhardt 41# Nathan Binkert 42# Gabe Black 43# Andreas Hansson 44 45##################################################################### 46# 47# Parameter description classes 48# 49# The _params dictionary in each class maps parameter names to either 50# a Param or a VectorParam object. These objects contain the 51# parameter description string, the parameter type, and the default 52# value (if any). The convert() method on these objects is used to 53# force whatever value is assigned to the parameter to the appropriate 54# type. 55# 56# Note that the default values are loaded into the class's attribute 57# space when the parameter dictionary is initialized (in 58# MetaSimObject._new_param()); after that point they aren't used. 59# 60##################################################################### 61 62import copy 63import datetime 64import re 65import sys 66import time 67import math 68 69import proxy 70import ticks 71from util import * 72 73def isSimObject(*args, **kwargs): 74 return SimObject.isSimObject(*args, **kwargs) 75 76def isSimObjectSequence(*args, **kwargs): 77 return SimObject.isSimObjectSequence(*args, **kwargs) 78 79def isSimObjectClass(*args, **kwargs): 80 return SimObject.isSimObjectClass(*args, **kwargs) 81 82allParams = {} 83 84class MetaParamValue(type): 85 def __new__(mcls, name, bases, dct): 86 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 87 assert name not in allParams 88 allParams[name] = cls 89 return cls 90 91 92# Dummy base class to identify types that are legitimate for SimObject 93# parameters. 94class ParamValue(object): 95 __metaclass__ = MetaParamValue 96 97 98 # Generate the code needed as a prerequisite for declaring a C++ 99 # object of this type. Typically generates one or more #include 100 # statements. Used when declaring parameters of this type. 101 @classmethod 102 def cxx_predecls(cls, code): 103 pass 104 105 # Generate the code needed as a prerequisite for including a 106 # reference to a C++ object of this type in a SWIG .i file. 107 # Typically generates one or more %import or %include statements. 108 @classmethod 109 def swig_predecls(cls, code): 110 pass 111 112 # default for printing to .ini file is regular string conversion. 113 # will be overridden in some cases 114 def ini_str(self): 115 return str(self) 116 117 # allows us to blithely call unproxy() on things without checking 118 # if they're really proxies or not 119 def unproxy(self, base): 120 return self 121 122# Regular parameter description. 123class ParamDesc(object): 124 def __init__(self, ptype_str, ptype, *args, **kwargs): 125 self.ptype_str = ptype_str 126 # remember ptype only if it is provided 127 if ptype != None: 128 self.ptype = ptype 129 130 if args: 131 if len(args) == 1: 132 self.desc = args[0] 133 elif len(args) == 2: 134 self.default = args[0] 135 self.desc = args[1] 136 else: 137 raise TypeError, 'too many arguments' 138 139 if kwargs.has_key('desc'): 140 assert(not hasattr(self, 'desc')) 141 self.desc = kwargs['desc'] 142 del kwargs['desc'] 143 144 if kwargs.has_key('default'): 145 assert(not hasattr(self, 'default')) 146 self.default = kwargs['default'] 147 del kwargs['default'] 148 149 if kwargs: 150 raise TypeError, 'extra unknown kwargs %s' % kwargs 151 152 if not hasattr(self, 'desc'): 153 raise TypeError, 'desc attribute missing' 154 155 def __getattr__(self, attr): 156 if attr == 'ptype': 157 ptype = SimObject.allClasses[self.ptype_str] 158 assert isSimObjectClass(ptype) 159 self.ptype = ptype 160 return ptype 161 162 raise AttributeError, "'%s' object has no attribute '%s'" % \ 163 (type(self).__name__, attr) 164 165 def convert(self, value): 166 if isinstance(value, proxy.BaseProxy): 167 value.set_param_desc(self) 168 return value 169 if not hasattr(self, 'ptype') and isNullPointer(value): 170 # deferred evaluation of SimObject; continue to defer if 171 # we're just assigning a null pointer 172 return value 173 if isinstance(value, self.ptype): 174 return value 175 if isNullPointer(value) and isSimObjectClass(self.ptype): 176 return value 177 return self.ptype(value) 178 179 def cxx_predecls(self, code): 180 code('#include <cstddef>') 181 self.ptype.cxx_predecls(code) 182 183 def swig_predecls(self, code): 184 self.ptype.swig_predecls(code) 185 186 def cxx_decl(self, code): 187 code('${{self.ptype.cxx_type}} ${{self.name}};') 188 189# Vector-valued parameter description. Just like ParamDesc, except 190# that the value is a vector (list) of the specified type instead of a 191# single value. 192 193class VectorParamValue(list): 194 __metaclass__ = MetaParamValue 195 def __setattr__(self, attr, value): 196 raise AttributeError, \ 197 "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 198 199 def ini_str(self): 200 return ' '.join([v.ini_str() for v in self]) 201 202 def getValue(self): 203 return [ v.getValue() for v in self ] 204 205 def unproxy(self, base): 206 if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 207 return self[0].unproxy(base) 208 else: 209 return [v.unproxy(base) for v in self] 210 211class SimObjectVector(VectorParamValue): 212 # support clone operation 213 def __call__(self, **kwargs): 214 return SimObjectVector([v(**kwargs) for v in self]) 215 216 def clear_parent(self, old_parent): 217 for v in self: 218 v.clear_parent(old_parent) 219 220 def set_parent(self, parent, name): 221 if len(self) == 1: 222 self[0].set_parent(parent, name) 223 else: 224 width = int(math.ceil(math.log(len(self))/math.log(10))) 225 for i,v in enumerate(self): 226 v.set_parent(parent, "%s%0*d" % (name, width, i)) 227 228 def has_parent(self): 229 return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 230 231 # return 'cpu0 cpu1' etc. for print_ini() 232 def get_name(self): 233 return ' '.join([v._name for v in self]) 234 235 # By iterating through the constituent members of the vector here 236 # we can nicely handle iterating over all a SimObject's children 237 # without having to provide lots of special functions on 238 # SimObjectVector directly. 239 def descendants(self): 240 for v in self: 241 for obj in v.descendants(): 242 yield obj 243 244 def get_config_as_dict(self): 245 a = [] 246 for v in self: 247 a.append(v.get_config_as_dict()) 248 return a 249 250class VectorParamDesc(ParamDesc): 251 # Convert assigned value to appropriate type. If the RHS is not a 252 # list or tuple, it generates a single-element list. 253 def convert(self, value): 254 if isinstance(value, (list, tuple)): 255 # list: coerce each element into new list 256 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 257 else: 258 # singleton: coerce to a single-element list 259 tmp_list = [ ParamDesc.convert(self, value) ] 260 261 if isSimObjectSequence(tmp_list): 262 return SimObjectVector(tmp_list) 263 else: 264 return VectorParamValue(tmp_list) 265 266 def swig_module_name(self): 267 return "%s_vector" % self.ptype_str 268 269 def swig_predecls(self, code): 270 code('%import "${{self.swig_module_name()}}.i"') 271 272 def swig_decl(self, code): 273 code('%module(package="m5.internal") ${{self.swig_module_name()}}') 274 code('%{') 275 self.ptype.cxx_predecls(code) 276 code('%}') 277 code() 278 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 279 code('%include "std_container.i"') 280 code() 281 self.ptype.swig_predecls(code) 282 code() 283 code('%include "std_vector.i"') 284 code() 285 286 ptype = self.ptype_str 287 cxx_type = self.ptype.cxx_type 288 289 code('''\ 290%typemap(in) std::vector< $cxx_type >::value_type { 291 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 292 if (SWIG_ConvertPtr($$input, (void **)&$$1, 293 $$descriptor($cxx_type), 0) == -1) { 294 return NULL; 295 } 296 } 297} 298 299%typemap(in) std::vector< $cxx_type >::value_type * { 300 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 301 if (SWIG_ConvertPtr($$input, (void **)&$$1, 302 $$descriptor($cxx_type *), 0) == -1) { 303 return NULL; 304 } 305 } 306} 307''') 308 309 code('%template(vector_$ptype) std::vector< $cxx_type >;') 310 311 def cxx_predecls(self, code): 312 code('#include <vector>') 313 self.ptype.cxx_predecls(code) 314 315 def cxx_decl(self, code): 316 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 317 318class ParamFactory(object): 319 def __init__(self, param_desc_class, ptype_str = None): 320 self.param_desc_class = param_desc_class 321 self.ptype_str = ptype_str 322 323 def __getattr__(self, attr): 324 if self.ptype_str: 325 attr = self.ptype_str + '.' + attr 326 return ParamFactory(self.param_desc_class, attr) 327 328 # E.g., Param.Int(5, "number of widgets") 329 def __call__(self, *args, **kwargs): 330 ptype = None 331 try: 332 ptype = allParams[self.ptype_str] 333 except KeyError: 334 # if name isn't defined yet, assume it's a SimObject, and 335 # try to resolve it later 336 pass 337 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 338 339Param = ParamFactory(ParamDesc) 340VectorParam = ParamFactory(VectorParamDesc) 341 342##################################################################### 343# 344# Parameter Types 345# 346# Though native Python types could be used to specify parameter types 347# (the 'ptype' field of the Param and VectorParam classes), it's more 348# flexible to define our own set of types. This gives us more control 349# over how Python expressions are converted to values (via the 350# __init__() constructor) and how these values are printed out (via 351# the __str__() conversion method). 352# 353##################################################################### 354 355# String-valued parameter. Just mixin the ParamValue class with the 356# built-in str class. 357class String(ParamValue,str): 358 cxx_type = 'std::string' 359 360 @classmethod 361 def cxx_predecls(self, code): 362 code('#include <string>') 363 364 @classmethod 365 def swig_predecls(cls, code): 366 code('%include "std_string.i"') 367 368 def getValue(self): 369 return self 370 371# superclass for "numeric" parameter values, to emulate math 372# operations in a type-safe way. e.g., a Latency times an int returns 373# a new Latency object. 374class NumericParamValue(ParamValue): 375 def __str__(self): 376 return str(self.value) 377 378 def __float__(self): 379 return float(self.value) 380 381 def __long__(self): 382 return long(self.value) 383 384 def __int__(self): 385 return int(self.value) 386 387 # hook for bounds checking 388 def _check(self): 389 return 390 391 def __mul__(self, other): 392 newobj = self.__class__(self) 393 newobj.value *= other 394 newobj._check() 395 return newobj 396 397 __rmul__ = __mul__ 398 399 def __div__(self, other): 400 newobj = self.__class__(self) 401 newobj.value /= other 402 newobj._check() 403 return newobj 404 405 def __sub__(self, other): 406 newobj = self.__class__(self) 407 newobj.value -= other 408 newobj._check() 409 return newobj 410 411# Metaclass for bounds-checked integer parameters. See CheckedInt. 412class CheckedIntType(MetaParamValue): 413 def __init__(cls, name, bases, dict): 414 super(CheckedIntType, cls).__init__(name, bases, dict) 415 416 # CheckedInt is an abstract base class, so we actually don't 417 # want to do any processing on it... the rest of this code is 418 # just for classes that derive from CheckedInt. 419 if name == 'CheckedInt': 420 return 421 422 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 423 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 424 panic("CheckedInt subclass %s must define either\n" \ 425 " 'min' and 'max' or 'size' and 'unsigned'\n", 426 name); 427 if cls.unsigned: 428 cls.min = 0 429 cls.max = 2 ** cls.size - 1 430 else: 431 cls.min = -(2 ** (cls.size - 1)) 432 cls.max = (2 ** (cls.size - 1)) - 1 433 434# Abstract superclass for bounds-checked integer parameters. This 435# class is subclassed to generate parameter classes with specific 436# bounds. Initialization of the min and max bounds is done in the 437# metaclass CheckedIntType.__init__. 438class CheckedInt(NumericParamValue): 439 __metaclass__ = CheckedIntType 440 441 def _check(self): 442 if not self.min <= self.value <= self.max: 443 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 444 (self.min, self.value, self.max) 445 446 def __init__(self, value): 447 if isinstance(value, str): 448 self.value = convert.toInteger(value) 449 elif isinstance(value, (int, long, float, NumericParamValue)): 450 self.value = long(value) 451 else: 452 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 453 % type(value).__name__ 454 self._check() 455 456 @classmethod 457 def cxx_predecls(cls, code): 458 # most derived types require this, so we just do it here once 459 code('#include "base/types.hh"') 460 461 @classmethod 462 def swig_predecls(cls, code): 463 # most derived types require this, so we just do it here once 464 code('%import "stdint.i"') 465 code('%import "base/types.hh"')
| 1# Copyright (c) 2012 ARM Limited 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Copyright (c) 2004-2006 The Regents of The University of Michigan 14# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 15# All rights reserved. 16# 17# Redistribution and use in source and binary forms, with or without 18# modification, are permitted provided that the following conditions are 19# met: redistributions of source code must retain the above copyright 20# notice, this list of conditions and the following disclaimer; 21# redistributions in binary form must reproduce the above copyright 22# notice, this list of conditions and the following disclaimer in the 23# documentation and/or other materials provided with the distribution; 24# neither the name of the copyright holders nor the names of its 25# contributors may be used to endorse or promote products derived from 26# this software without specific prior written permission. 27# 28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39# 40# Authors: Steve Reinhardt 41# Nathan Binkert 42# Gabe Black 43# Andreas Hansson 44 45##################################################################### 46# 47# Parameter description classes 48# 49# The _params dictionary in each class maps parameter names to either 50# a Param or a VectorParam object. These objects contain the 51# parameter description string, the parameter type, and the default 52# value (if any). The convert() method on these objects is used to 53# force whatever value is assigned to the parameter to the appropriate 54# type. 55# 56# Note that the default values are loaded into the class's attribute 57# space when the parameter dictionary is initialized (in 58# MetaSimObject._new_param()); after that point they aren't used. 59# 60##################################################################### 61 62import copy 63import datetime 64import re 65import sys 66import time 67import math 68 69import proxy 70import ticks 71from util import * 72 73def isSimObject(*args, **kwargs): 74 return SimObject.isSimObject(*args, **kwargs) 75 76def isSimObjectSequence(*args, **kwargs): 77 return SimObject.isSimObjectSequence(*args, **kwargs) 78 79def isSimObjectClass(*args, **kwargs): 80 return SimObject.isSimObjectClass(*args, **kwargs) 81 82allParams = {} 83 84class MetaParamValue(type): 85 def __new__(mcls, name, bases, dct): 86 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 87 assert name not in allParams 88 allParams[name] = cls 89 return cls 90 91 92# Dummy base class to identify types that are legitimate for SimObject 93# parameters. 94class ParamValue(object): 95 __metaclass__ = MetaParamValue 96 97 98 # Generate the code needed as a prerequisite for declaring a C++ 99 # object of this type. Typically generates one or more #include 100 # statements. Used when declaring parameters of this type. 101 @classmethod 102 def cxx_predecls(cls, code): 103 pass 104 105 # Generate the code needed as a prerequisite for including a 106 # reference to a C++ object of this type in a SWIG .i file. 107 # Typically generates one or more %import or %include statements. 108 @classmethod 109 def swig_predecls(cls, code): 110 pass 111 112 # default for printing to .ini file is regular string conversion. 113 # will be overridden in some cases 114 def ini_str(self): 115 return str(self) 116 117 # allows us to blithely call unproxy() on things without checking 118 # if they're really proxies or not 119 def unproxy(self, base): 120 return self 121 122# Regular parameter description. 123class ParamDesc(object): 124 def __init__(self, ptype_str, ptype, *args, **kwargs): 125 self.ptype_str = ptype_str 126 # remember ptype only if it is provided 127 if ptype != None: 128 self.ptype = ptype 129 130 if args: 131 if len(args) == 1: 132 self.desc = args[0] 133 elif len(args) == 2: 134 self.default = args[0] 135 self.desc = args[1] 136 else: 137 raise TypeError, 'too many arguments' 138 139 if kwargs.has_key('desc'): 140 assert(not hasattr(self, 'desc')) 141 self.desc = kwargs['desc'] 142 del kwargs['desc'] 143 144 if kwargs.has_key('default'): 145 assert(not hasattr(self, 'default')) 146 self.default = kwargs['default'] 147 del kwargs['default'] 148 149 if kwargs: 150 raise TypeError, 'extra unknown kwargs %s' % kwargs 151 152 if not hasattr(self, 'desc'): 153 raise TypeError, 'desc attribute missing' 154 155 def __getattr__(self, attr): 156 if attr == 'ptype': 157 ptype = SimObject.allClasses[self.ptype_str] 158 assert isSimObjectClass(ptype) 159 self.ptype = ptype 160 return ptype 161 162 raise AttributeError, "'%s' object has no attribute '%s'" % \ 163 (type(self).__name__, attr) 164 165 def convert(self, value): 166 if isinstance(value, proxy.BaseProxy): 167 value.set_param_desc(self) 168 return value 169 if not hasattr(self, 'ptype') and isNullPointer(value): 170 # deferred evaluation of SimObject; continue to defer if 171 # we're just assigning a null pointer 172 return value 173 if isinstance(value, self.ptype): 174 return value 175 if isNullPointer(value) and isSimObjectClass(self.ptype): 176 return value 177 return self.ptype(value) 178 179 def cxx_predecls(self, code): 180 code('#include <cstddef>') 181 self.ptype.cxx_predecls(code) 182 183 def swig_predecls(self, code): 184 self.ptype.swig_predecls(code) 185 186 def cxx_decl(self, code): 187 code('${{self.ptype.cxx_type}} ${{self.name}};') 188 189# Vector-valued parameter description. Just like ParamDesc, except 190# that the value is a vector (list) of the specified type instead of a 191# single value. 192 193class VectorParamValue(list): 194 __metaclass__ = MetaParamValue 195 def __setattr__(self, attr, value): 196 raise AttributeError, \ 197 "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 198 199 def ini_str(self): 200 return ' '.join([v.ini_str() for v in self]) 201 202 def getValue(self): 203 return [ v.getValue() for v in self ] 204 205 def unproxy(self, base): 206 if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 207 return self[0].unproxy(base) 208 else: 209 return [v.unproxy(base) for v in self] 210 211class SimObjectVector(VectorParamValue): 212 # support clone operation 213 def __call__(self, **kwargs): 214 return SimObjectVector([v(**kwargs) for v in self]) 215 216 def clear_parent(self, old_parent): 217 for v in self: 218 v.clear_parent(old_parent) 219 220 def set_parent(self, parent, name): 221 if len(self) == 1: 222 self[0].set_parent(parent, name) 223 else: 224 width = int(math.ceil(math.log(len(self))/math.log(10))) 225 for i,v in enumerate(self): 226 v.set_parent(parent, "%s%0*d" % (name, width, i)) 227 228 def has_parent(self): 229 return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 230 231 # return 'cpu0 cpu1' etc. for print_ini() 232 def get_name(self): 233 return ' '.join([v._name for v in self]) 234 235 # By iterating through the constituent members of the vector here 236 # we can nicely handle iterating over all a SimObject's children 237 # without having to provide lots of special functions on 238 # SimObjectVector directly. 239 def descendants(self): 240 for v in self: 241 for obj in v.descendants(): 242 yield obj 243 244 def get_config_as_dict(self): 245 a = [] 246 for v in self: 247 a.append(v.get_config_as_dict()) 248 return a 249 250class VectorParamDesc(ParamDesc): 251 # Convert assigned value to appropriate type. If the RHS is not a 252 # list or tuple, it generates a single-element list. 253 def convert(self, value): 254 if isinstance(value, (list, tuple)): 255 # list: coerce each element into new list 256 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 257 else: 258 # singleton: coerce to a single-element list 259 tmp_list = [ ParamDesc.convert(self, value) ] 260 261 if isSimObjectSequence(tmp_list): 262 return SimObjectVector(tmp_list) 263 else: 264 return VectorParamValue(tmp_list) 265 266 def swig_module_name(self): 267 return "%s_vector" % self.ptype_str 268 269 def swig_predecls(self, code): 270 code('%import "${{self.swig_module_name()}}.i"') 271 272 def swig_decl(self, code): 273 code('%module(package="m5.internal") ${{self.swig_module_name()}}') 274 code('%{') 275 self.ptype.cxx_predecls(code) 276 code('%}') 277 code() 278 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 279 code('%include "std_container.i"') 280 code() 281 self.ptype.swig_predecls(code) 282 code() 283 code('%include "std_vector.i"') 284 code() 285 286 ptype = self.ptype_str 287 cxx_type = self.ptype.cxx_type 288 289 code('''\ 290%typemap(in) std::vector< $cxx_type >::value_type { 291 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 292 if (SWIG_ConvertPtr($$input, (void **)&$$1, 293 $$descriptor($cxx_type), 0) == -1) { 294 return NULL; 295 } 296 } 297} 298 299%typemap(in) std::vector< $cxx_type >::value_type * { 300 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 301 if (SWIG_ConvertPtr($$input, (void **)&$$1, 302 $$descriptor($cxx_type *), 0) == -1) { 303 return NULL; 304 } 305 } 306} 307''') 308 309 code('%template(vector_$ptype) std::vector< $cxx_type >;') 310 311 def cxx_predecls(self, code): 312 code('#include <vector>') 313 self.ptype.cxx_predecls(code) 314 315 def cxx_decl(self, code): 316 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 317 318class ParamFactory(object): 319 def __init__(self, param_desc_class, ptype_str = None): 320 self.param_desc_class = param_desc_class 321 self.ptype_str = ptype_str 322 323 def __getattr__(self, attr): 324 if self.ptype_str: 325 attr = self.ptype_str + '.' + attr 326 return ParamFactory(self.param_desc_class, attr) 327 328 # E.g., Param.Int(5, "number of widgets") 329 def __call__(self, *args, **kwargs): 330 ptype = None 331 try: 332 ptype = allParams[self.ptype_str] 333 except KeyError: 334 # if name isn't defined yet, assume it's a SimObject, and 335 # try to resolve it later 336 pass 337 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 338 339Param = ParamFactory(ParamDesc) 340VectorParam = ParamFactory(VectorParamDesc) 341 342##################################################################### 343# 344# Parameter Types 345# 346# Though native Python types could be used to specify parameter types 347# (the 'ptype' field of the Param and VectorParam classes), it's more 348# flexible to define our own set of types. This gives us more control 349# over how Python expressions are converted to values (via the 350# __init__() constructor) and how these values are printed out (via 351# the __str__() conversion method). 352# 353##################################################################### 354 355# String-valued parameter. Just mixin the ParamValue class with the 356# built-in str class. 357class String(ParamValue,str): 358 cxx_type = 'std::string' 359 360 @classmethod 361 def cxx_predecls(self, code): 362 code('#include <string>') 363 364 @classmethod 365 def swig_predecls(cls, code): 366 code('%include "std_string.i"') 367 368 def getValue(self): 369 return self 370 371# superclass for "numeric" parameter values, to emulate math 372# operations in a type-safe way. e.g., a Latency times an int returns 373# a new Latency object. 374class NumericParamValue(ParamValue): 375 def __str__(self): 376 return str(self.value) 377 378 def __float__(self): 379 return float(self.value) 380 381 def __long__(self): 382 return long(self.value) 383 384 def __int__(self): 385 return int(self.value) 386 387 # hook for bounds checking 388 def _check(self): 389 return 390 391 def __mul__(self, other): 392 newobj = self.__class__(self) 393 newobj.value *= other 394 newobj._check() 395 return newobj 396 397 __rmul__ = __mul__ 398 399 def __div__(self, other): 400 newobj = self.__class__(self) 401 newobj.value /= other 402 newobj._check() 403 return newobj 404 405 def __sub__(self, other): 406 newobj = self.__class__(self) 407 newobj.value -= other 408 newobj._check() 409 return newobj 410 411# Metaclass for bounds-checked integer parameters. See CheckedInt. 412class CheckedIntType(MetaParamValue): 413 def __init__(cls, name, bases, dict): 414 super(CheckedIntType, cls).__init__(name, bases, dict) 415 416 # CheckedInt is an abstract base class, so we actually don't 417 # want to do any processing on it... the rest of this code is 418 # just for classes that derive from CheckedInt. 419 if name == 'CheckedInt': 420 return 421 422 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 423 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 424 panic("CheckedInt subclass %s must define either\n" \ 425 " 'min' and 'max' or 'size' and 'unsigned'\n", 426 name); 427 if cls.unsigned: 428 cls.min = 0 429 cls.max = 2 ** cls.size - 1 430 else: 431 cls.min = -(2 ** (cls.size - 1)) 432 cls.max = (2 ** (cls.size - 1)) - 1 433 434# Abstract superclass for bounds-checked integer parameters. This 435# class is subclassed to generate parameter classes with specific 436# bounds. Initialization of the min and max bounds is done in the 437# metaclass CheckedIntType.__init__. 438class CheckedInt(NumericParamValue): 439 __metaclass__ = CheckedIntType 440 441 def _check(self): 442 if not self.min <= self.value <= self.max: 443 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 444 (self.min, self.value, self.max) 445 446 def __init__(self, value): 447 if isinstance(value, str): 448 self.value = convert.toInteger(value) 449 elif isinstance(value, (int, long, float, NumericParamValue)): 450 self.value = long(value) 451 else: 452 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 453 % type(value).__name__ 454 self._check() 455 456 @classmethod 457 def cxx_predecls(cls, code): 458 # most derived types require this, so we just do it here once 459 code('#include "base/types.hh"') 460 461 @classmethod 462 def swig_predecls(cls, code): 463 # most derived types require this, so we just do it here once 464 code('%import "stdint.i"') 465 code('%import "base/types.hh"')
|
492class Float(ParamValue, float): 493 cxx_type = 'double' 494 495 def __init__(self, value): 496 if isinstance(value, (int, long, float, NumericParamValue, Float)): 497 self.value = float(value) 498 else: 499 raise TypeError, "Can't convert object of type %s to Float" \ 500 % type(value).__name__ 501 502 def getValue(self): 503 return float(self.value) 504 505class MemorySize(CheckedInt): 506 cxx_type = 'uint64_t' 507 size = 64 508 unsigned = True 509 def __init__(self, value): 510 if isinstance(value, MemorySize): 511 self.value = value.value 512 else: 513 self.value = convert.toMemorySize(value) 514 self._check() 515 516class MemorySize32(CheckedInt): 517 cxx_type = 'uint32_t' 518 size = 32 519 unsigned = True 520 def __init__(self, value): 521 if isinstance(value, MemorySize): 522 self.value = value.value 523 else: 524 self.value = convert.toMemorySize(value) 525 self._check() 526 527class Addr(CheckedInt): 528 cxx_type = 'Addr' 529 size = 64 530 unsigned = True 531 def __init__(self, value): 532 if isinstance(value, Addr): 533 self.value = value.value 534 else: 535 try: 536 self.value = convert.toMemorySize(value) 537 except TypeError: 538 self.value = long(value) 539 self._check() 540 def __add__(self, other): 541 if isinstance(other, Addr): 542 return self.value + other.value 543 else: 544 return self.value + other 545 546 547class MetaRange(MetaParamValue): 548 def __init__(cls, name, bases, dict): 549 super(MetaRange, cls).__init__(name, bases, dict) 550 if name == 'Range': 551 return 552 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 553 554class Range(ParamValue): 555 __metaclass__ = MetaRange 556 type = Int # default; can be overridden in subclasses 557 def __init__(self, *args, **kwargs): 558 def handle_kwargs(self, kwargs): 559 if 'end' in kwargs: 560 self.second = self.type(kwargs.pop('end')) 561 elif 'size' in kwargs: 562 self.second = self.first + self.type(kwargs.pop('size')) - 1 563 else: 564 raise TypeError, "Either end or size must be specified" 565 566 if len(args) == 0: 567 self.first = self.type(kwargs.pop('start')) 568 handle_kwargs(self, kwargs) 569 570 elif len(args) == 1: 571 if kwargs: 572 self.first = self.type(args[0]) 573 handle_kwargs(self, kwargs) 574 elif isinstance(args[0], Range): 575 self.first = self.type(args[0].first) 576 self.second = self.type(args[0].second) 577 elif isinstance(args[0], (list, tuple)): 578 self.first = self.type(args[0][0]) 579 self.second = self.type(args[0][1]) 580 else: 581 self.first = self.type(0) 582 self.second = self.type(args[0]) - 1 583 584 elif len(args) == 2: 585 self.first = self.type(args[0]) 586 self.second = self.type(args[1]) 587 else: 588 raise TypeError, "Too many arguments specified" 589 590 if kwargs: 591 raise TypeError, "too many keywords: %s" % kwargs.keys() 592 593 def __str__(self): 594 return '%s:%s' % (self.first, self.second) 595 596 @classmethod 597 def cxx_predecls(cls, code): 598 cls.type.cxx_predecls(code) 599 code('#include "base/range.hh"') 600 601 @classmethod 602 def swig_predecls(cls, code): 603 cls.type.swig_predecls(code) 604 code('%import "python/swig/range.i"') 605 606class AddrRange(Range): 607 type = Addr 608 609 def getValue(self): 610 from m5.internal.range import AddrRange 611 612 value = AddrRange() 613 value.start = long(self.first) 614 value.end = long(self.second) 615 return value 616 617class TickRange(Range): 618 type = Tick 619 620 def getValue(self): 621 from m5.internal.range import TickRange 622 623 value = TickRange() 624 value.start = long(self.first) 625 value.end = long(self.second) 626 return value 627 628# Boolean parameter type. Python doesn't let you subclass bool, since 629# it doesn't want to let you create multiple instances of True and 630# False. Thus this is a little more complicated than String. 631class Bool(ParamValue): 632 cxx_type = 'bool' 633 def __init__(self, value): 634 try: 635 self.value = convert.toBool(value) 636 except TypeError: 637 self.value = bool(value) 638 639 def getValue(self): 640 return bool(self.value) 641 642 def __str__(self): 643 return str(self.value) 644 645 # implement truth value testing for Bool parameters so that these params 646 # evaluate correctly during the python configuration phase 647 def __nonzero__(self): 648 return bool(self.value) 649 650 def ini_str(self): 651 if self.value: 652 return 'true' 653 return 'false' 654 655def IncEthernetAddr(addr, val = 1): 656 bytes = map(lambda x: int(x, 16), addr.split(':')) 657 bytes[5] += val 658 for i in (5, 4, 3, 2, 1): 659 val,rem = divmod(bytes[i], 256) 660 bytes[i] = rem 661 if val == 0: 662 break 663 bytes[i - 1] += val 664 assert(bytes[0] <= 255) 665 return ':'.join(map(lambda x: '%02x' % x, bytes)) 666 667_NextEthernetAddr = "00:90:00:00:00:01" 668def NextEthernetAddr(): 669 global _NextEthernetAddr 670 671 value = _NextEthernetAddr 672 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 673 return value 674 675class EthernetAddr(ParamValue): 676 cxx_type = 'Net::EthAddr' 677 678 @classmethod 679 def cxx_predecls(cls, code): 680 code('#include "base/inet.hh"') 681 682 @classmethod 683 def swig_predecls(cls, code): 684 code('%include "python/swig/inet.i"') 685 686 def __init__(self, value): 687 if value == NextEthernetAddr: 688 self.value = value 689 return 690 691 if not isinstance(value, str): 692 raise TypeError, "expected an ethernet address and didn't get one" 693 694 bytes = value.split(':') 695 if len(bytes) != 6: 696 raise TypeError, 'invalid ethernet address %s' % value 697 698 for byte in bytes: 699 if not 0 <= int(byte) <= 0xff: 700 raise TypeError, 'invalid ethernet address %s' % value 701 702 self.value = value 703 704 def unproxy(self, base): 705 if self.value == NextEthernetAddr: 706 return EthernetAddr(self.value()) 707 return self 708 709 def getValue(self): 710 from m5.internal.params import EthAddr 711 return EthAddr(self.value) 712 713 def ini_str(self): 714 return self.value 715 716# When initializing an IpAddress, pass in an existing IpAddress, a string of 717# the form "a.b.c.d", or an integer representing an IP. 718class IpAddress(ParamValue): 719 cxx_type = 'Net::IpAddress' 720 721 @classmethod 722 def cxx_predecls(cls, code): 723 code('#include "base/inet.hh"') 724 725 @classmethod 726 def swig_predecls(cls, code): 727 code('%include "python/swig/inet.i"') 728 729 def __init__(self, value): 730 if isinstance(value, IpAddress): 731 self.ip = value.ip 732 else: 733 try: 734 self.ip = convert.toIpAddress(value) 735 except TypeError: 736 self.ip = long(value) 737 self.verifyIp() 738 739 def __str__(self): 740 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 741 return '%d.%d.%d.%d' % tuple(tup) 742 743 def __eq__(self, other): 744 if isinstance(other, IpAddress): 745 return self.ip == other.ip 746 elif isinstance(other, str): 747 try: 748 return self.ip == convert.toIpAddress(other) 749 except: 750 return False 751 else: 752 return self.ip == other 753 754 def __ne__(self, other): 755 return not (self == other) 756 757 def verifyIp(self): 758 if self.ip < 0 or self.ip >= (1 << 32): 759 raise TypeError, "invalid ip address %#08x" % self.ip 760 761 def getValue(self): 762 from m5.internal.params import IpAddress 763 return IpAddress(self.ip) 764 765# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 766# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 767# positional or keyword arguments. 768class IpNetmask(IpAddress): 769 cxx_type = 'Net::IpNetmask' 770 771 @classmethod 772 def cxx_predecls(cls, code): 773 code('#include "base/inet.hh"') 774 775 @classmethod 776 def swig_predecls(cls, code): 777 code('%include "python/swig/inet.i"') 778 779 def __init__(self, *args, **kwargs): 780 def handle_kwarg(self, kwargs, key, elseVal = None): 781 if key in kwargs: 782 setattr(self, key, kwargs.pop(key)) 783 elif elseVal: 784 setattr(self, key, elseVal) 785 else: 786 raise TypeError, "No value set for %s" % key 787 788 if len(args) == 0: 789 handle_kwarg(self, kwargs, 'ip') 790 handle_kwarg(self, kwargs, 'netmask') 791 792 elif len(args) == 1: 793 if kwargs: 794 if not 'ip' in kwargs and not 'netmask' in kwargs: 795 raise TypeError, "Invalid arguments" 796 handle_kwarg(self, kwargs, 'ip', args[0]) 797 handle_kwarg(self, kwargs, 'netmask', args[0]) 798 elif isinstance(args[0], IpNetmask): 799 self.ip = args[0].ip 800 self.netmask = args[0].netmask 801 else: 802 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 803 804 elif len(args) == 2: 805 self.ip = args[0] 806 self.netmask = args[1] 807 else: 808 raise TypeError, "Too many arguments specified" 809 810 if kwargs: 811 raise TypeError, "Too many keywords: %s" % kwargs.keys() 812 813 self.verify() 814 815 def __str__(self): 816 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 817 818 def __eq__(self, other): 819 if isinstance(other, IpNetmask): 820 return self.ip == other.ip and self.netmask == other.netmask 821 elif isinstance(other, str): 822 try: 823 return (self.ip, self.netmask) == convert.toIpNetmask(other) 824 except: 825 return False 826 else: 827 return False 828 829 def verify(self): 830 self.verifyIp() 831 if self.netmask < 0 or self.netmask > 32: 832 raise TypeError, "invalid netmask %d" % netmask 833 834 def getValue(self): 835 from m5.internal.params import IpNetmask 836 return IpNetmask(self.ip, self.netmask) 837 838# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 839# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 840class IpWithPort(IpAddress): 841 cxx_type = 'Net::IpWithPort' 842 843 @classmethod 844 def cxx_predecls(cls, code): 845 code('#include "base/inet.hh"') 846 847 @classmethod 848 def swig_predecls(cls, code): 849 code('%include "python/swig/inet.i"') 850 851 def __init__(self, *args, **kwargs): 852 def handle_kwarg(self, kwargs, key, elseVal = None): 853 if key in kwargs: 854 setattr(self, key, kwargs.pop(key)) 855 elif elseVal: 856 setattr(self, key, elseVal) 857 else: 858 raise TypeError, "No value set for %s" % key 859 860 if len(args) == 0: 861 handle_kwarg(self, kwargs, 'ip') 862 handle_kwarg(self, kwargs, 'port') 863 864 elif len(args) == 1: 865 if kwargs: 866 if not 'ip' in kwargs and not 'port' in kwargs: 867 raise TypeError, "Invalid arguments" 868 handle_kwarg(self, kwargs, 'ip', args[0]) 869 handle_kwarg(self, kwargs, 'port', args[0]) 870 elif isinstance(args[0], IpWithPort): 871 self.ip = args[0].ip 872 self.port = args[0].port 873 else: 874 (self.ip, self.port) = convert.toIpWithPort(args[0]) 875 876 elif len(args) == 2: 877 self.ip = args[0] 878 self.port = args[1] 879 else: 880 raise TypeError, "Too many arguments specified" 881 882 if kwargs: 883 raise TypeError, "Too many keywords: %s" % kwargs.keys() 884 885 self.verify() 886 887 def __str__(self): 888 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 889 890 def __eq__(self, other): 891 if isinstance(other, IpWithPort): 892 return self.ip == other.ip and self.port == other.port 893 elif isinstance(other, str): 894 try: 895 return (self.ip, self.port) == convert.toIpWithPort(other) 896 except: 897 return False 898 else: 899 return False 900 901 def verify(self): 902 self.verifyIp() 903 if self.port < 0 or self.port > 0xffff: 904 raise TypeError, "invalid port %d" % self.port 905 906 def getValue(self): 907 from m5.internal.params import IpWithPort 908 return IpWithPort(self.ip, self.port) 909 910time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 911 "%a %b %d %H:%M:%S %Z %Y", 912 "%Y/%m/%d %H:%M:%S", 913 "%Y/%m/%d %H:%M", 914 "%Y/%m/%d", 915 "%m/%d/%Y %H:%M:%S", 916 "%m/%d/%Y %H:%M", 917 "%m/%d/%Y", 918 "%m/%d/%y %H:%M:%S", 919 "%m/%d/%y %H:%M", 920 "%m/%d/%y"] 921 922 923def parse_time(value): 924 from time import gmtime, strptime, struct_time, time 925 from datetime import datetime, date 926 927 if isinstance(value, struct_time): 928 return value 929 930 if isinstance(value, (int, long)): 931 return gmtime(value) 932 933 if isinstance(value, (datetime, date)): 934 return value.timetuple() 935 936 if isinstance(value, str): 937 if value in ('Now', 'Today'): 938 return time.gmtime(time.time()) 939 940 for format in time_formats: 941 try: 942 return strptime(value, format) 943 except ValueError: 944 pass 945 946 raise ValueError, "Could not parse '%s' as a time" % value 947 948class Time(ParamValue): 949 cxx_type = 'tm' 950 951 @classmethod 952 def cxx_predecls(cls, code): 953 code('#include <time.h>') 954 955 @classmethod 956 def swig_predecls(cls, code): 957 code('%include "python/swig/time.i"') 958 959 def __init__(self, value): 960 self.value = parse_time(value) 961 962 def getValue(self): 963 from m5.internal.params import tm 964 965 c_time = tm() 966 py_time = self.value 967 968 # UNIX is years since 1900 969 c_time.tm_year = py_time.tm_year - 1900; 970 971 # Python starts at 1, UNIX starts at 0 972 c_time.tm_mon = py_time.tm_mon - 1; 973 c_time.tm_mday = py_time.tm_mday; 974 c_time.tm_hour = py_time.tm_hour; 975 c_time.tm_min = py_time.tm_min; 976 c_time.tm_sec = py_time.tm_sec; 977 978 # Python has 0 as Monday, UNIX is 0 as sunday 979 c_time.tm_wday = py_time.tm_wday + 1 980 if c_time.tm_wday > 6: 981 c_time.tm_wday -= 7; 982 983 # Python starts at 1, Unix starts at 0 984 c_time.tm_yday = py_time.tm_yday - 1; 985 986 return c_time 987 988 def __str__(self): 989 return time.asctime(self.value) 990 991 def ini_str(self): 992 return str(self) 993 994 def get_config_as_dict(self): 995 return str(self) 996 997# Enumerated types are a little more complex. The user specifies the 998# type as Enum(foo) where foo is either a list or dictionary of 999# alternatives (typically strings, but not necessarily so). (In the 1000# long run, the integer value of the parameter will be the list index 1001# or the corresponding dictionary value. For now, since we only check 1002# that the alternative is valid and then spit it into a .ini file, 1003# there's not much point in using the dictionary.) 1004 1005# What Enum() must do is generate a new type encapsulating the 1006# provided list/dictionary so that specific values of the parameter 1007# can be instances of that type. We define two hidden internal 1008# classes (_ListEnum and _DictEnum) to serve as base classes, then 1009# derive the new type from the appropriate base class on the fly. 1010 1011allEnums = {} 1012# Metaclass for Enum types 1013class MetaEnum(MetaParamValue): 1014 def __new__(mcls, name, bases, dict): 1015 assert name not in allEnums 1016 1017 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1018 allEnums[name] = cls 1019 return cls 1020 1021 def __init__(cls, name, bases, init_dict): 1022 if init_dict.has_key('map'): 1023 if not isinstance(cls.map, dict): 1024 raise TypeError, "Enum-derived class attribute 'map' " \ 1025 "must be of type dict" 1026 # build list of value strings from map 1027 cls.vals = cls.map.keys() 1028 cls.vals.sort() 1029 elif init_dict.has_key('vals'): 1030 if not isinstance(cls.vals, list): 1031 raise TypeError, "Enum-derived class attribute 'vals' " \ 1032 "must be of type list" 1033 # build string->value map from vals sequence 1034 cls.map = {} 1035 for idx,val in enumerate(cls.vals): 1036 cls.map[val] = idx 1037 else: 1038 raise TypeError, "Enum-derived class must define "\ 1039 "attribute 'map' or 'vals'" 1040 1041 cls.cxx_type = 'Enums::%s' % name 1042 1043 super(MetaEnum, cls).__init__(name, bases, init_dict) 1044 1045 # Generate C++ class declaration for this enum type. 1046 # Note that we wrap the enum in a class/struct to act as a namespace, 1047 # so that the enum strings can be brief w/o worrying about collisions. 1048 def cxx_decl(cls, code): 1049 name = cls.__name__ 1050 code('''\ 1051#ifndef __ENUM__${name}__ 1052#define __ENUM__${name}__ 1053 1054namespace Enums { 1055 enum $name { 1056''') 1057 code.indent(2) 1058 for val in cls.vals: 1059 code('$val = ${{cls.map[val]}},') 1060 code('Num_$name = ${{len(cls.vals)}}') 1061 code.dedent(2) 1062 code('''\ 1063 }; 1064extern const char *${name}Strings[Num_${name}]; 1065} 1066 1067#endif // __ENUM__${name}__ 1068''') 1069 1070 def cxx_def(cls, code): 1071 name = cls.__name__ 1072 code('''\ 1073#include "enums/$name.hh" 1074namespace Enums { 1075 const char *${name}Strings[Num_${name}] = 1076 { 1077''') 1078 code.indent(2) 1079 for val in cls.vals: 1080 code('"$val",') 1081 code.dedent(2) 1082 code(''' 1083 }; 1084} // namespace Enums 1085''') 1086 1087 def swig_decl(cls, code): 1088 name = cls.__name__ 1089 code('''\ 1090%module(package="m5.internal") enum_$name 1091 1092%{ 1093#include "enums/$name.hh" 1094%} 1095 1096%include "enums/$name.hh" 1097''') 1098 1099 1100# Base class for enum types. 1101class Enum(ParamValue): 1102 __metaclass__ = MetaEnum 1103 vals = [] 1104 1105 def __init__(self, value): 1106 if value not in self.map: 1107 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1108 % (value, self.vals) 1109 self.value = value 1110 1111 @classmethod 1112 def cxx_predecls(cls, code): 1113 code('#include "enums/$0.hh"', cls.__name__) 1114 1115 @classmethod 1116 def swig_predecls(cls, code): 1117 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1118 1119 def getValue(self): 1120 return int(self.map[self.value]) 1121 1122 def __str__(self): 1123 return self.value 1124 1125# how big does a rounding error need to be before we warn about it? 1126frequency_tolerance = 0.001 # 0.1% 1127 1128class TickParamValue(NumericParamValue): 1129 cxx_type = 'Tick' 1130 1131 @classmethod 1132 def cxx_predecls(cls, code): 1133 code('#include "base/types.hh"') 1134 1135 @classmethod 1136 def swig_predecls(cls, code): 1137 code('%import "stdint.i"') 1138 code('%import "base/types.hh"') 1139 1140 def getValue(self): 1141 return long(self.value) 1142 1143class Latency(TickParamValue): 1144 def __init__(self, value): 1145 if isinstance(value, (Latency, Clock)): 1146 self.ticks = value.ticks 1147 self.value = value.value 1148 elif isinstance(value, Frequency): 1149 self.ticks = value.ticks 1150 self.value = 1.0 / value.value 1151 elif value.endswith('t'): 1152 self.ticks = True 1153 self.value = int(value[:-1]) 1154 else: 1155 self.ticks = False 1156 self.value = convert.toLatency(value) 1157 1158 def __getattr__(self, attr): 1159 if attr in ('latency', 'period'): 1160 return self 1161 if attr == 'frequency': 1162 return Frequency(self) 1163 raise AttributeError, "Latency object has no attribute '%s'" % attr 1164 1165 def getValue(self): 1166 if self.ticks or self.value == 0: 1167 value = self.value 1168 else: 1169 value = ticks.fromSeconds(self.value) 1170 return long(value) 1171 1172 # convert latency to ticks 1173 def ini_str(self): 1174 return '%d' % self.getValue() 1175 1176class Frequency(TickParamValue): 1177 def __init__(self, value): 1178 if isinstance(value, (Latency, Clock)): 1179 if value.value == 0: 1180 self.value = 0 1181 else: 1182 self.value = 1.0 / value.value 1183 self.ticks = value.ticks 1184 elif isinstance(value, Frequency): 1185 self.value = value.value 1186 self.ticks = value.ticks 1187 else: 1188 self.ticks = False 1189 self.value = convert.toFrequency(value) 1190 1191 def __getattr__(self, attr): 1192 if attr == 'frequency': 1193 return self 1194 if attr in ('latency', 'period'): 1195 return Latency(self) 1196 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1197 1198 # convert latency to ticks 1199 def getValue(self): 1200 if self.ticks or self.value == 0: 1201 value = self.value 1202 else: 1203 value = ticks.fromSeconds(1.0 / self.value) 1204 return long(value) 1205 1206 def ini_str(self): 1207 return '%d' % self.getValue() 1208 1209# A generic frequency and/or Latency value. Value is stored as a latency, 1210# but to avoid ambiguity this object does not support numeric ops (* or /). 1211# An explicit conversion to a Latency or Frequency must be made first. 1212class Clock(ParamValue): 1213 cxx_type = 'Tick' 1214 1215 @classmethod 1216 def cxx_predecls(cls, code): 1217 code('#include "base/types.hh"') 1218 1219 @classmethod 1220 def swig_predecls(cls, code): 1221 code('%import "stdint.i"') 1222 code('%import "base/types.hh"') 1223 1224 def __init__(self, value): 1225 if isinstance(value, (Latency, Clock)): 1226 self.ticks = value.ticks 1227 self.value = value.value 1228 elif isinstance(value, Frequency): 1229 self.ticks = value.ticks 1230 self.value = 1.0 / value.value 1231 elif value.endswith('t'): 1232 self.ticks = True 1233 self.value = int(value[:-1]) 1234 else: 1235 self.ticks = False 1236 self.value = convert.anyToLatency(value) 1237 1238 def __getattr__(self, attr): 1239 if attr == 'frequency': 1240 return Frequency(self) 1241 if attr in ('latency', 'period'): 1242 return Latency(self) 1243 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1244 1245 def getValue(self): 1246 return self.period.getValue() 1247 1248 def ini_str(self): 1249 return self.period.ini_str() 1250 1251class NetworkBandwidth(float,ParamValue): 1252 cxx_type = 'float' 1253 def __new__(cls, value): 1254 # convert to bits per second 1255 val = convert.toNetworkBandwidth(value) 1256 return super(cls, NetworkBandwidth).__new__(cls, val) 1257 1258 def __str__(self): 1259 return str(self.val) 1260 1261 def getValue(self): 1262 # convert to seconds per byte 1263 value = 8.0 / float(self) 1264 # convert to ticks per byte 1265 value = ticks.fromSeconds(value) 1266 return float(value) 1267 1268 def ini_str(self): 1269 return '%f' % self.getValue() 1270 1271class MemoryBandwidth(float,ParamValue): 1272 cxx_type = 'float' 1273 def __new__(cls, value): 1274 # convert to bytes per second 1275 val = convert.toMemoryBandwidth(value) 1276 return super(cls, MemoryBandwidth).__new__(cls, val) 1277 1278 def __str__(self): 1279 return str(self.val) 1280 1281 def getValue(self): 1282 # convert to seconds per byte 1283 value = float(self) 1284 if value: 1285 value = 1.0 / float(self) 1286 # convert to ticks per byte 1287 value = ticks.fromSeconds(value) 1288 return float(value) 1289 1290 def ini_str(self): 1291 return '%f' % self.getValue() 1292 1293# 1294# "Constants"... handy aliases for various values. 1295# 1296 1297# Special class for NULL pointers. Note the special check in 1298# make_param_value() above that lets these be assigned where a 1299# SimObject is required. 1300# only one copy of a particular node 1301class NullSimObject(object): 1302 __metaclass__ = Singleton 1303 1304 def __call__(cls): 1305 return cls 1306 1307 def _instantiate(self, parent = None, path = ''): 1308 pass 1309 1310 def ini_str(self): 1311 return 'Null' 1312 1313 def unproxy(self, base): 1314 return self 1315 1316 def set_path(self, parent, name): 1317 pass 1318 1319 def __str__(self): 1320 return 'Null' 1321 1322 def getValue(self): 1323 return None 1324 1325# The only instance you'll ever need... 1326NULL = NullSimObject() 1327 1328def isNullPointer(value): 1329 return isinstance(value, NullSimObject) 1330 1331# Some memory range specifications use this as a default upper bound. 1332MaxAddr = Addr.max 1333MaxTick = Tick.max 1334AllMemory = AddrRange(0, MaxAddr) 1335 1336 1337##################################################################### 1338# 1339# Port objects 1340# 1341# Ports are used to interconnect objects in the memory system. 1342# 1343##################################################################### 1344 1345# Port reference: encapsulates a reference to a particular port on a 1346# particular SimObject. 1347class PortRef(object): 1348 def __init__(self, simobj, name, role): 1349 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1350 self.simobj = simobj 1351 self.name = name 1352 self.role = role 1353 self.peer = None # not associated with another port yet 1354 self.ccConnected = False # C++ port connection done? 1355 self.index = -1 # always -1 for non-vector ports 1356 1357 def __str__(self): 1358 return '%s.%s' % (self.simobj, self.name) 1359 1360 def __len__(self): 1361 # Return the number of connected ports, i.e. 0 is we have no 1362 # peer and 1 if we do. 1363 return int(self.peer != None) 1364 1365 # for config.ini, print peer's name (not ours) 1366 def ini_str(self): 1367 return str(self.peer) 1368 1369 # for config.json 1370 def get_config_as_dict(self): 1371 return {'role' : self.role, 'peer' : str(self.peer)} 1372 1373 def __getattr__(self, attr): 1374 if attr == 'peerObj': 1375 # shorthand for proxies 1376 return self.peer.simobj 1377 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1378 (self.__class__.__name__, attr) 1379 1380 # Full connection is symmetric (both ways). Called via 1381 # SimObject.__setattr__ as a result of a port assignment, e.g., 1382 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1383 # e.g., "obj1.portA[3] = obj2.portB". 1384 def connect(self, other): 1385 if isinstance(other, VectorPortRef): 1386 # reference to plain VectorPort is implicit append 1387 other = other._get_next() 1388 if self.peer and not proxy.isproxy(self.peer): 1389 fatal("Port %s is already connected to %s, cannot connect %s\n", 1390 self, self.peer, other); 1391 self.peer = other 1392 if proxy.isproxy(other): 1393 other.set_param_desc(PortParamDesc()) 1394 elif isinstance(other, PortRef): 1395 if other.peer is not self: 1396 other.connect(self) 1397 else: 1398 raise TypeError, \ 1399 "assigning non-port reference '%s' to port '%s'" \ 1400 % (other, self) 1401 1402 def clone(self, simobj, memo): 1403 if memo.has_key(self): 1404 return memo[self] 1405 newRef = copy.copy(self) 1406 memo[self] = newRef 1407 newRef.simobj = simobj 1408 assert(isSimObject(newRef.simobj)) 1409 if self.peer and not proxy.isproxy(self.peer): 1410 peerObj = self.peer.simobj(_memo=memo) 1411 newRef.peer = self.peer.clone(peerObj, memo) 1412 assert(not isinstance(newRef.peer, VectorPortRef)) 1413 return newRef 1414 1415 def unproxy(self, simobj): 1416 assert(simobj is self.simobj) 1417 if proxy.isproxy(self.peer): 1418 try: 1419 realPeer = self.peer.unproxy(self.simobj) 1420 except: 1421 print "Error in unproxying port '%s' of %s" % \ 1422 (self.name, self.simobj.path()) 1423 raise 1424 self.connect(realPeer) 1425 1426 # Call C++ to create corresponding port connection between C++ objects 1427 def ccConnect(self): 1428 from m5.internal.pyobject import connectPorts 1429 1430 if self.role == 'SLAVE': 1431 # do nothing and let the master take care of it 1432 return 1433 1434 if self.ccConnected: # already done this 1435 return 1436 peer = self.peer 1437 if not self.peer: # nothing to connect to 1438 return 1439 1440 # check that we connect a master to a slave 1441 if self.role == peer.role: 1442 raise TypeError, \ 1443 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1444 % (peer, self, self.role) 1445 1446 try: 1447 # self is always the master and peer the slave 1448 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1449 peer.simobj.getCCObject(), peer.name, peer.index) 1450 except: 1451 print "Error connecting port %s.%s to %s.%s" % \ 1452 (self.simobj.path(), self.name, 1453 peer.simobj.path(), peer.name) 1454 raise 1455 self.ccConnected = True 1456 peer.ccConnected = True 1457 1458# A reference to an individual element of a VectorPort... much like a 1459# PortRef, but has an index. 1460class VectorPortElementRef(PortRef): 1461 def __init__(self, simobj, name, role, index): 1462 PortRef.__init__(self, simobj, name, role) 1463 self.index = index 1464 1465 def __str__(self): 1466 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1467 1468# A reference to a complete vector-valued port (not just a single element). 1469# Can be indexed to retrieve individual VectorPortElementRef instances. 1470class VectorPortRef(object): 1471 def __init__(self, simobj, name, role): 1472 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1473 self.simobj = simobj 1474 self.name = name 1475 self.role = role 1476 self.elements = [] 1477 1478 def __str__(self): 1479 return '%s.%s[:]' % (self.simobj, self.name) 1480 1481 def __len__(self): 1482 # Return the number of connected peers, corresponding the the 1483 # length of the elements. 1484 return len(self.elements) 1485 1486 # for config.ini, print peer's name (not ours) 1487 def ini_str(self): 1488 return ' '.join([el.ini_str() for el in self.elements]) 1489 1490 # for config.json 1491 def get_config_as_dict(self): 1492 return {'role' : self.role, 1493 'peer' : [el.ini_str() for el in self.elements]} 1494 1495 def __getitem__(self, key): 1496 if not isinstance(key, int): 1497 raise TypeError, "VectorPort index must be integer" 1498 if key >= len(self.elements): 1499 # need to extend list 1500 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1501 for i in range(len(self.elements), key+1)] 1502 self.elements.extend(ext) 1503 return self.elements[key] 1504 1505 def _get_next(self): 1506 return self[len(self.elements)] 1507 1508 def __setitem__(self, key, value): 1509 if not isinstance(key, int): 1510 raise TypeError, "VectorPort index must be integer" 1511 self[key].connect(value) 1512 1513 def connect(self, other): 1514 if isinstance(other, (list, tuple)): 1515 # Assign list of port refs to vector port. 1516 # For now, append them... not sure if that's the right semantics 1517 # or if it should replace the current vector. 1518 for ref in other: 1519 self._get_next().connect(ref) 1520 else: 1521 # scalar assignment to plain VectorPort is implicit append 1522 self._get_next().connect(other) 1523 1524 def clone(self, simobj, memo): 1525 if memo.has_key(self): 1526 return memo[self] 1527 newRef = copy.copy(self) 1528 memo[self] = newRef 1529 newRef.simobj = simobj 1530 assert(isSimObject(newRef.simobj)) 1531 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1532 return newRef 1533 1534 def unproxy(self, simobj): 1535 [el.unproxy(simobj) for el in self.elements] 1536 1537 def ccConnect(self): 1538 [el.ccConnect() for el in self.elements] 1539 1540# Port description object. Like a ParamDesc object, this represents a 1541# logical port in the SimObject class, not a particular port on a 1542# SimObject instance. The latter are represented by PortRef objects. 1543class Port(object): 1544 # Generate a PortRef for this port on the given SimObject with the 1545 # given name 1546 def makeRef(self, simobj): 1547 return PortRef(simobj, self.name, self.role) 1548 1549 # Connect an instance of this port (on the given SimObject with 1550 # the given name) with the port described by the supplied PortRef 1551 def connect(self, simobj, ref): 1552 self.makeRef(simobj).connect(ref) 1553 1554 # No need for any pre-declarations at the moment as we merely rely 1555 # on an unsigned int. 1556 def cxx_predecls(self, code): 1557 pass 1558 1559 # Declare an unsigned int with the same name as the port, that 1560 # will eventually hold the number of connected ports (and thus the 1561 # number of elements for a VectorPort). 1562 def cxx_decl(self, code): 1563 code('unsigned int port_${{self.name}}_connection_count;') 1564 1565class MasterPort(Port): 1566 # MasterPort("description") 1567 def __init__(self, *args): 1568 if len(args) == 1: 1569 self.desc = args[0] 1570 self.role = 'MASTER' 1571 else: 1572 raise TypeError, 'wrong number of arguments' 1573 1574class SlavePort(Port): 1575 # SlavePort("description") 1576 def __init__(self, *args): 1577 if len(args) == 1: 1578 self.desc = args[0] 1579 self.role = 'SLAVE' 1580 else: 1581 raise TypeError, 'wrong number of arguments' 1582 1583# VectorPort description object. Like Port, but represents a vector 1584# of connections (e.g., as on a Bus). 1585class VectorPort(Port): 1586 def __init__(self, *args): 1587 self.isVec = True 1588 1589 def makeRef(self, simobj): 1590 return VectorPortRef(simobj, self.name, self.role) 1591 1592class VectorMasterPort(VectorPort): 1593 # VectorMasterPort("description") 1594 def __init__(self, *args): 1595 if len(args) == 1: 1596 self.desc = args[0] 1597 self.role = 'MASTER' 1598 VectorPort.__init__(self, *args) 1599 else: 1600 raise TypeError, 'wrong number of arguments' 1601 1602class VectorSlavePort(VectorPort): 1603 # VectorSlavePort("description") 1604 def __init__(self, *args): 1605 if len(args) == 1: 1606 self.desc = args[0] 1607 self.role = 'SLAVE' 1608 VectorPort.__init__(self, *args) 1609 else: 1610 raise TypeError, 'wrong number of arguments' 1611 1612# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1613# proxy objects (via set_param_desc()) so that proxy error messages 1614# make sense. 1615class PortParamDesc(object): 1616 __metaclass__ = Singleton 1617 1618 ptype_str = 'Port' 1619 ptype = Port 1620 1621baseEnums = allEnums.copy() 1622baseParams = allParams.copy() 1623 1624def clear(): 1625 global allEnums, allParams 1626 1627 allEnums = baseEnums.copy() 1628 allParams = baseParams.copy() 1629 1630__all__ = ['Param', 'VectorParam', 1631 'Enum', 'Bool', 'String', 'Float', 1632 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1633 'Int32', 'UInt32', 'Int64', 'UInt64', 1634 'Counter', 'Addr', 'Tick', 'Percent', 1635 'TcpPort', 'UdpPort', 'EthernetAddr', 1636 'IpAddress', 'IpNetmask', 'IpWithPort', 1637 'MemorySize', 'MemorySize32', 1638 'Latency', 'Frequency', 'Clock', 1639 'NetworkBandwidth', 'MemoryBandwidth', 1640 'Range', 'AddrRange', 'TickRange', 1641 'MaxAddr', 'MaxTick', 'AllMemory', 1642 'Time', 1643 'NextEthernetAddr', 'NULL', 1644 'MasterPort', 'SlavePort', 1645 'VectorMasterPort', 'VectorSlavePort'] 1646 1647import SimObject
| 498class Float(ParamValue, float): 499 cxx_type = 'double' 500 501 def __init__(self, value): 502 if isinstance(value, (int, long, float, NumericParamValue, Float)): 503 self.value = float(value) 504 else: 505 raise TypeError, "Can't convert object of type %s to Float" \ 506 % type(value).__name__ 507 508 def getValue(self): 509 return float(self.value) 510 511class MemorySize(CheckedInt): 512 cxx_type = 'uint64_t' 513 size = 64 514 unsigned = True 515 def __init__(self, value): 516 if isinstance(value, MemorySize): 517 self.value = value.value 518 else: 519 self.value = convert.toMemorySize(value) 520 self._check() 521 522class MemorySize32(CheckedInt): 523 cxx_type = 'uint32_t' 524 size = 32 525 unsigned = True 526 def __init__(self, value): 527 if isinstance(value, MemorySize): 528 self.value = value.value 529 else: 530 self.value = convert.toMemorySize(value) 531 self._check() 532 533class Addr(CheckedInt): 534 cxx_type = 'Addr' 535 size = 64 536 unsigned = True 537 def __init__(self, value): 538 if isinstance(value, Addr): 539 self.value = value.value 540 else: 541 try: 542 self.value = convert.toMemorySize(value) 543 except TypeError: 544 self.value = long(value) 545 self._check() 546 def __add__(self, other): 547 if isinstance(other, Addr): 548 return self.value + other.value 549 else: 550 return self.value + other 551 552 553class MetaRange(MetaParamValue): 554 def __init__(cls, name, bases, dict): 555 super(MetaRange, cls).__init__(name, bases, dict) 556 if name == 'Range': 557 return 558 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 559 560class Range(ParamValue): 561 __metaclass__ = MetaRange 562 type = Int # default; can be overridden in subclasses 563 def __init__(self, *args, **kwargs): 564 def handle_kwargs(self, kwargs): 565 if 'end' in kwargs: 566 self.second = self.type(kwargs.pop('end')) 567 elif 'size' in kwargs: 568 self.second = self.first + self.type(kwargs.pop('size')) - 1 569 else: 570 raise TypeError, "Either end or size must be specified" 571 572 if len(args) == 0: 573 self.first = self.type(kwargs.pop('start')) 574 handle_kwargs(self, kwargs) 575 576 elif len(args) == 1: 577 if kwargs: 578 self.first = self.type(args[0]) 579 handle_kwargs(self, kwargs) 580 elif isinstance(args[0], Range): 581 self.first = self.type(args[0].first) 582 self.second = self.type(args[0].second) 583 elif isinstance(args[0], (list, tuple)): 584 self.first = self.type(args[0][0]) 585 self.second = self.type(args[0][1]) 586 else: 587 self.first = self.type(0) 588 self.second = self.type(args[0]) - 1 589 590 elif len(args) == 2: 591 self.first = self.type(args[0]) 592 self.second = self.type(args[1]) 593 else: 594 raise TypeError, "Too many arguments specified" 595 596 if kwargs: 597 raise TypeError, "too many keywords: %s" % kwargs.keys() 598 599 def __str__(self): 600 return '%s:%s' % (self.first, self.second) 601 602 @classmethod 603 def cxx_predecls(cls, code): 604 cls.type.cxx_predecls(code) 605 code('#include "base/range.hh"') 606 607 @classmethod 608 def swig_predecls(cls, code): 609 cls.type.swig_predecls(code) 610 code('%import "python/swig/range.i"') 611 612class AddrRange(Range): 613 type = Addr 614 615 def getValue(self): 616 from m5.internal.range import AddrRange 617 618 value = AddrRange() 619 value.start = long(self.first) 620 value.end = long(self.second) 621 return value 622 623class TickRange(Range): 624 type = Tick 625 626 def getValue(self): 627 from m5.internal.range import TickRange 628 629 value = TickRange() 630 value.start = long(self.first) 631 value.end = long(self.second) 632 return value 633 634# Boolean parameter type. Python doesn't let you subclass bool, since 635# it doesn't want to let you create multiple instances of True and 636# False. Thus this is a little more complicated than String. 637class Bool(ParamValue): 638 cxx_type = 'bool' 639 def __init__(self, value): 640 try: 641 self.value = convert.toBool(value) 642 except TypeError: 643 self.value = bool(value) 644 645 def getValue(self): 646 return bool(self.value) 647 648 def __str__(self): 649 return str(self.value) 650 651 # implement truth value testing for Bool parameters so that these params 652 # evaluate correctly during the python configuration phase 653 def __nonzero__(self): 654 return bool(self.value) 655 656 def ini_str(self): 657 if self.value: 658 return 'true' 659 return 'false' 660 661def IncEthernetAddr(addr, val = 1): 662 bytes = map(lambda x: int(x, 16), addr.split(':')) 663 bytes[5] += val 664 for i in (5, 4, 3, 2, 1): 665 val,rem = divmod(bytes[i], 256) 666 bytes[i] = rem 667 if val == 0: 668 break 669 bytes[i - 1] += val 670 assert(bytes[0] <= 255) 671 return ':'.join(map(lambda x: '%02x' % x, bytes)) 672 673_NextEthernetAddr = "00:90:00:00:00:01" 674def NextEthernetAddr(): 675 global _NextEthernetAddr 676 677 value = _NextEthernetAddr 678 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 679 return value 680 681class EthernetAddr(ParamValue): 682 cxx_type = 'Net::EthAddr' 683 684 @classmethod 685 def cxx_predecls(cls, code): 686 code('#include "base/inet.hh"') 687 688 @classmethod 689 def swig_predecls(cls, code): 690 code('%include "python/swig/inet.i"') 691 692 def __init__(self, value): 693 if value == NextEthernetAddr: 694 self.value = value 695 return 696 697 if not isinstance(value, str): 698 raise TypeError, "expected an ethernet address and didn't get one" 699 700 bytes = value.split(':') 701 if len(bytes) != 6: 702 raise TypeError, 'invalid ethernet address %s' % value 703 704 for byte in bytes: 705 if not 0 <= int(byte) <= 0xff: 706 raise TypeError, 'invalid ethernet address %s' % value 707 708 self.value = value 709 710 def unproxy(self, base): 711 if self.value == NextEthernetAddr: 712 return EthernetAddr(self.value()) 713 return self 714 715 def getValue(self): 716 from m5.internal.params import EthAddr 717 return EthAddr(self.value) 718 719 def ini_str(self): 720 return self.value 721 722# When initializing an IpAddress, pass in an existing IpAddress, a string of 723# the form "a.b.c.d", or an integer representing an IP. 724class IpAddress(ParamValue): 725 cxx_type = 'Net::IpAddress' 726 727 @classmethod 728 def cxx_predecls(cls, code): 729 code('#include "base/inet.hh"') 730 731 @classmethod 732 def swig_predecls(cls, code): 733 code('%include "python/swig/inet.i"') 734 735 def __init__(self, value): 736 if isinstance(value, IpAddress): 737 self.ip = value.ip 738 else: 739 try: 740 self.ip = convert.toIpAddress(value) 741 except TypeError: 742 self.ip = long(value) 743 self.verifyIp() 744 745 def __str__(self): 746 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 747 return '%d.%d.%d.%d' % tuple(tup) 748 749 def __eq__(self, other): 750 if isinstance(other, IpAddress): 751 return self.ip == other.ip 752 elif isinstance(other, str): 753 try: 754 return self.ip == convert.toIpAddress(other) 755 except: 756 return False 757 else: 758 return self.ip == other 759 760 def __ne__(self, other): 761 return not (self == other) 762 763 def verifyIp(self): 764 if self.ip < 0 or self.ip >= (1 << 32): 765 raise TypeError, "invalid ip address %#08x" % self.ip 766 767 def getValue(self): 768 from m5.internal.params import IpAddress 769 return IpAddress(self.ip) 770 771# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 772# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 773# positional or keyword arguments. 774class IpNetmask(IpAddress): 775 cxx_type = 'Net::IpNetmask' 776 777 @classmethod 778 def cxx_predecls(cls, code): 779 code('#include "base/inet.hh"') 780 781 @classmethod 782 def swig_predecls(cls, code): 783 code('%include "python/swig/inet.i"') 784 785 def __init__(self, *args, **kwargs): 786 def handle_kwarg(self, kwargs, key, elseVal = None): 787 if key in kwargs: 788 setattr(self, key, kwargs.pop(key)) 789 elif elseVal: 790 setattr(self, key, elseVal) 791 else: 792 raise TypeError, "No value set for %s" % key 793 794 if len(args) == 0: 795 handle_kwarg(self, kwargs, 'ip') 796 handle_kwarg(self, kwargs, 'netmask') 797 798 elif len(args) == 1: 799 if kwargs: 800 if not 'ip' in kwargs and not 'netmask' in kwargs: 801 raise TypeError, "Invalid arguments" 802 handle_kwarg(self, kwargs, 'ip', args[0]) 803 handle_kwarg(self, kwargs, 'netmask', args[0]) 804 elif isinstance(args[0], IpNetmask): 805 self.ip = args[0].ip 806 self.netmask = args[0].netmask 807 else: 808 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 809 810 elif len(args) == 2: 811 self.ip = args[0] 812 self.netmask = args[1] 813 else: 814 raise TypeError, "Too many arguments specified" 815 816 if kwargs: 817 raise TypeError, "Too many keywords: %s" % kwargs.keys() 818 819 self.verify() 820 821 def __str__(self): 822 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 823 824 def __eq__(self, other): 825 if isinstance(other, IpNetmask): 826 return self.ip == other.ip and self.netmask == other.netmask 827 elif isinstance(other, str): 828 try: 829 return (self.ip, self.netmask) == convert.toIpNetmask(other) 830 except: 831 return False 832 else: 833 return False 834 835 def verify(self): 836 self.verifyIp() 837 if self.netmask < 0 or self.netmask > 32: 838 raise TypeError, "invalid netmask %d" % netmask 839 840 def getValue(self): 841 from m5.internal.params import IpNetmask 842 return IpNetmask(self.ip, self.netmask) 843 844# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 845# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 846class IpWithPort(IpAddress): 847 cxx_type = 'Net::IpWithPort' 848 849 @classmethod 850 def cxx_predecls(cls, code): 851 code('#include "base/inet.hh"') 852 853 @classmethod 854 def swig_predecls(cls, code): 855 code('%include "python/swig/inet.i"') 856 857 def __init__(self, *args, **kwargs): 858 def handle_kwarg(self, kwargs, key, elseVal = None): 859 if key in kwargs: 860 setattr(self, key, kwargs.pop(key)) 861 elif elseVal: 862 setattr(self, key, elseVal) 863 else: 864 raise TypeError, "No value set for %s" % key 865 866 if len(args) == 0: 867 handle_kwarg(self, kwargs, 'ip') 868 handle_kwarg(self, kwargs, 'port') 869 870 elif len(args) == 1: 871 if kwargs: 872 if not 'ip' in kwargs and not 'port' in kwargs: 873 raise TypeError, "Invalid arguments" 874 handle_kwarg(self, kwargs, 'ip', args[0]) 875 handle_kwarg(self, kwargs, 'port', args[0]) 876 elif isinstance(args[0], IpWithPort): 877 self.ip = args[0].ip 878 self.port = args[0].port 879 else: 880 (self.ip, self.port) = convert.toIpWithPort(args[0]) 881 882 elif len(args) == 2: 883 self.ip = args[0] 884 self.port = args[1] 885 else: 886 raise TypeError, "Too many arguments specified" 887 888 if kwargs: 889 raise TypeError, "Too many keywords: %s" % kwargs.keys() 890 891 self.verify() 892 893 def __str__(self): 894 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 895 896 def __eq__(self, other): 897 if isinstance(other, IpWithPort): 898 return self.ip == other.ip and self.port == other.port 899 elif isinstance(other, str): 900 try: 901 return (self.ip, self.port) == convert.toIpWithPort(other) 902 except: 903 return False 904 else: 905 return False 906 907 def verify(self): 908 self.verifyIp() 909 if self.port < 0 or self.port > 0xffff: 910 raise TypeError, "invalid port %d" % self.port 911 912 def getValue(self): 913 from m5.internal.params import IpWithPort 914 return IpWithPort(self.ip, self.port) 915 916time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 917 "%a %b %d %H:%M:%S %Z %Y", 918 "%Y/%m/%d %H:%M:%S", 919 "%Y/%m/%d %H:%M", 920 "%Y/%m/%d", 921 "%m/%d/%Y %H:%M:%S", 922 "%m/%d/%Y %H:%M", 923 "%m/%d/%Y", 924 "%m/%d/%y %H:%M:%S", 925 "%m/%d/%y %H:%M", 926 "%m/%d/%y"] 927 928 929def parse_time(value): 930 from time import gmtime, strptime, struct_time, time 931 from datetime import datetime, date 932 933 if isinstance(value, struct_time): 934 return value 935 936 if isinstance(value, (int, long)): 937 return gmtime(value) 938 939 if isinstance(value, (datetime, date)): 940 return value.timetuple() 941 942 if isinstance(value, str): 943 if value in ('Now', 'Today'): 944 return time.gmtime(time.time()) 945 946 for format in time_formats: 947 try: 948 return strptime(value, format) 949 except ValueError: 950 pass 951 952 raise ValueError, "Could not parse '%s' as a time" % value 953 954class Time(ParamValue): 955 cxx_type = 'tm' 956 957 @classmethod 958 def cxx_predecls(cls, code): 959 code('#include <time.h>') 960 961 @classmethod 962 def swig_predecls(cls, code): 963 code('%include "python/swig/time.i"') 964 965 def __init__(self, value): 966 self.value = parse_time(value) 967 968 def getValue(self): 969 from m5.internal.params import tm 970 971 c_time = tm() 972 py_time = self.value 973 974 # UNIX is years since 1900 975 c_time.tm_year = py_time.tm_year - 1900; 976 977 # Python starts at 1, UNIX starts at 0 978 c_time.tm_mon = py_time.tm_mon - 1; 979 c_time.tm_mday = py_time.tm_mday; 980 c_time.tm_hour = py_time.tm_hour; 981 c_time.tm_min = py_time.tm_min; 982 c_time.tm_sec = py_time.tm_sec; 983 984 # Python has 0 as Monday, UNIX is 0 as sunday 985 c_time.tm_wday = py_time.tm_wday + 1 986 if c_time.tm_wday > 6: 987 c_time.tm_wday -= 7; 988 989 # Python starts at 1, Unix starts at 0 990 c_time.tm_yday = py_time.tm_yday - 1; 991 992 return c_time 993 994 def __str__(self): 995 return time.asctime(self.value) 996 997 def ini_str(self): 998 return str(self) 999 1000 def get_config_as_dict(self): 1001 return str(self) 1002 1003# Enumerated types are a little more complex. The user specifies the 1004# type as Enum(foo) where foo is either a list or dictionary of 1005# alternatives (typically strings, but not necessarily so). (In the 1006# long run, the integer value of the parameter will be the list index 1007# or the corresponding dictionary value. For now, since we only check 1008# that the alternative is valid and then spit it into a .ini file, 1009# there's not much point in using the dictionary.) 1010 1011# What Enum() must do is generate a new type encapsulating the 1012# provided list/dictionary so that specific values of the parameter 1013# can be instances of that type. We define two hidden internal 1014# classes (_ListEnum and _DictEnum) to serve as base classes, then 1015# derive the new type from the appropriate base class on the fly. 1016 1017allEnums = {} 1018# Metaclass for Enum types 1019class MetaEnum(MetaParamValue): 1020 def __new__(mcls, name, bases, dict): 1021 assert name not in allEnums 1022 1023 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1024 allEnums[name] = cls 1025 return cls 1026 1027 def __init__(cls, name, bases, init_dict): 1028 if init_dict.has_key('map'): 1029 if not isinstance(cls.map, dict): 1030 raise TypeError, "Enum-derived class attribute 'map' " \ 1031 "must be of type dict" 1032 # build list of value strings from map 1033 cls.vals = cls.map.keys() 1034 cls.vals.sort() 1035 elif init_dict.has_key('vals'): 1036 if not isinstance(cls.vals, list): 1037 raise TypeError, "Enum-derived class attribute 'vals' " \ 1038 "must be of type list" 1039 # build string->value map from vals sequence 1040 cls.map = {} 1041 for idx,val in enumerate(cls.vals): 1042 cls.map[val] = idx 1043 else: 1044 raise TypeError, "Enum-derived class must define "\ 1045 "attribute 'map' or 'vals'" 1046 1047 cls.cxx_type = 'Enums::%s' % name 1048 1049 super(MetaEnum, cls).__init__(name, bases, init_dict) 1050 1051 # Generate C++ class declaration for this enum type. 1052 # Note that we wrap the enum in a class/struct to act as a namespace, 1053 # so that the enum strings can be brief w/o worrying about collisions. 1054 def cxx_decl(cls, code): 1055 name = cls.__name__ 1056 code('''\ 1057#ifndef __ENUM__${name}__ 1058#define __ENUM__${name}__ 1059 1060namespace Enums { 1061 enum $name { 1062''') 1063 code.indent(2) 1064 for val in cls.vals: 1065 code('$val = ${{cls.map[val]}},') 1066 code('Num_$name = ${{len(cls.vals)}}') 1067 code.dedent(2) 1068 code('''\ 1069 }; 1070extern const char *${name}Strings[Num_${name}]; 1071} 1072 1073#endif // __ENUM__${name}__ 1074''') 1075 1076 def cxx_def(cls, code): 1077 name = cls.__name__ 1078 code('''\ 1079#include "enums/$name.hh" 1080namespace Enums { 1081 const char *${name}Strings[Num_${name}] = 1082 { 1083''') 1084 code.indent(2) 1085 for val in cls.vals: 1086 code('"$val",') 1087 code.dedent(2) 1088 code(''' 1089 }; 1090} // namespace Enums 1091''') 1092 1093 def swig_decl(cls, code): 1094 name = cls.__name__ 1095 code('''\ 1096%module(package="m5.internal") enum_$name 1097 1098%{ 1099#include "enums/$name.hh" 1100%} 1101 1102%include "enums/$name.hh" 1103''') 1104 1105 1106# Base class for enum types. 1107class Enum(ParamValue): 1108 __metaclass__ = MetaEnum 1109 vals = [] 1110 1111 def __init__(self, value): 1112 if value not in self.map: 1113 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1114 % (value, self.vals) 1115 self.value = value 1116 1117 @classmethod 1118 def cxx_predecls(cls, code): 1119 code('#include "enums/$0.hh"', cls.__name__) 1120 1121 @classmethod 1122 def swig_predecls(cls, code): 1123 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1124 1125 def getValue(self): 1126 return int(self.map[self.value]) 1127 1128 def __str__(self): 1129 return self.value 1130 1131# how big does a rounding error need to be before we warn about it? 1132frequency_tolerance = 0.001 # 0.1% 1133 1134class TickParamValue(NumericParamValue): 1135 cxx_type = 'Tick' 1136 1137 @classmethod 1138 def cxx_predecls(cls, code): 1139 code('#include "base/types.hh"') 1140 1141 @classmethod 1142 def swig_predecls(cls, code): 1143 code('%import "stdint.i"') 1144 code('%import "base/types.hh"') 1145 1146 def getValue(self): 1147 return long(self.value) 1148 1149class Latency(TickParamValue): 1150 def __init__(self, value): 1151 if isinstance(value, (Latency, Clock)): 1152 self.ticks = value.ticks 1153 self.value = value.value 1154 elif isinstance(value, Frequency): 1155 self.ticks = value.ticks 1156 self.value = 1.0 / value.value 1157 elif value.endswith('t'): 1158 self.ticks = True 1159 self.value = int(value[:-1]) 1160 else: 1161 self.ticks = False 1162 self.value = convert.toLatency(value) 1163 1164 def __getattr__(self, attr): 1165 if attr in ('latency', 'period'): 1166 return self 1167 if attr == 'frequency': 1168 return Frequency(self) 1169 raise AttributeError, "Latency object has no attribute '%s'" % attr 1170 1171 def getValue(self): 1172 if self.ticks or self.value == 0: 1173 value = self.value 1174 else: 1175 value = ticks.fromSeconds(self.value) 1176 return long(value) 1177 1178 # convert latency to ticks 1179 def ini_str(self): 1180 return '%d' % self.getValue() 1181 1182class Frequency(TickParamValue): 1183 def __init__(self, value): 1184 if isinstance(value, (Latency, Clock)): 1185 if value.value == 0: 1186 self.value = 0 1187 else: 1188 self.value = 1.0 / value.value 1189 self.ticks = value.ticks 1190 elif isinstance(value, Frequency): 1191 self.value = value.value 1192 self.ticks = value.ticks 1193 else: 1194 self.ticks = False 1195 self.value = convert.toFrequency(value) 1196 1197 def __getattr__(self, attr): 1198 if attr == 'frequency': 1199 return self 1200 if attr in ('latency', 'period'): 1201 return Latency(self) 1202 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1203 1204 # convert latency to ticks 1205 def getValue(self): 1206 if self.ticks or self.value == 0: 1207 value = self.value 1208 else: 1209 value = ticks.fromSeconds(1.0 / self.value) 1210 return long(value) 1211 1212 def ini_str(self): 1213 return '%d' % self.getValue() 1214 1215# A generic frequency and/or Latency value. Value is stored as a latency, 1216# but to avoid ambiguity this object does not support numeric ops (* or /). 1217# An explicit conversion to a Latency or Frequency must be made first. 1218class Clock(ParamValue): 1219 cxx_type = 'Tick' 1220 1221 @classmethod 1222 def cxx_predecls(cls, code): 1223 code('#include "base/types.hh"') 1224 1225 @classmethod 1226 def swig_predecls(cls, code): 1227 code('%import "stdint.i"') 1228 code('%import "base/types.hh"') 1229 1230 def __init__(self, value): 1231 if isinstance(value, (Latency, Clock)): 1232 self.ticks = value.ticks 1233 self.value = value.value 1234 elif isinstance(value, Frequency): 1235 self.ticks = value.ticks 1236 self.value = 1.0 / value.value 1237 elif value.endswith('t'): 1238 self.ticks = True 1239 self.value = int(value[:-1]) 1240 else: 1241 self.ticks = False 1242 self.value = convert.anyToLatency(value) 1243 1244 def __getattr__(self, attr): 1245 if attr == 'frequency': 1246 return Frequency(self) 1247 if attr in ('latency', 'period'): 1248 return Latency(self) 1249 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1250 1251 def getValue(self): 1252 return self.period.getValue() 1253 1254 def ini_str(self): 1255 return self.period.ini_str() 1256 1257class NetworkBandwidth(float,ParamValue): 1258 cxx_type = 'float' 1259 def __new__(cls, value): 1260 # convert to bits per second 1261 val = convert.toNetworkBandwidth(value) 1262 return super(cls, NetworkBandwidth).__new__(cls, val) 1263 1264 def __str__(self): 1265 return str(self.val) 1266 1267 def getValue(self): 1268 # convert to seconds per byte 1269 value = 8.0 / float(self) 1270 # convert to ticks per byte 1271 value = ticks.fromSeconds(value) 1272 return float(value) 1273 1274 def ini_str(self): 1275 return '%f' % self.getValue() 1276 1277class MemoryBandwidth(float,ParamValue): 1278 cxx_type = 'float' 1279 def __new__(cls, value): 1280 # convert to bytes per second 1281 val = convert.toMemoryBandwidth(value) 1282 return super(cls, MemoryBandwidth).__new__(cls, val) 1283 1284 def __str__(self): 1285 return str(self.val) 1286 1287 def getValue(self): 1288 # convert to seconds per byte 1289 value = float(self) 1290 if value: 1291 value = 1.0 / float(self) 1292 # convert to ticks per byte 1293 value = ticks.fromSeconds(value) 1294 return float(value) 1295 1296 def ini_str(self): 1297 return '%f' % self.getValue() 1298 1299# 1300# "Constants"... handy aliases for various values. 1301# 1302 1303# Special class for NULL pointers. Note the special check in 1304# make_param_value() above that lets these be assigned where a 1305# SimObject is required. 1306# only one copy of a particular node 1307class NullSimObject(object): 1308 __metaclass__ = Singleton 1309 1310 def __call__(cls): 1311 return cls 1312 1313 def _instantiate(self, parent = None, path = ''): 1314 pass 1315 1316 def ini_str(self): 1317 return 'Null' 1318 1319 def unproxy(self, base): 1320 return self 1321 1322 def set_path(self, parent, name): 1323 pass 1324 1325 def __str__(self): 1326 return 'Null' 1327 1328 def getValue(self): 1329 return None 1330 1331# The only instance you'll ever need... 1332NULL = NullSimObject() 1333 1334def isNullPointer(value): 1335 return isinstance(value, NullSimObject) 1336 1337# Some memory range specifications use this as a default upper bound. 1338MaxAddr = Addr.max 1339MaxTick = Tick.max 1340AllMemory = AddrRange(0, MaxAddr) 1341 1342 1343##################################################################### 1344# 1345# Port objects 1346# 1347# Ports are used to interconnect objects in the memory system. 1348# 1349##################################################################### 1350 1351# Port reference: encapsulates a reference to a particular port on a 1352# particular SimObject. 1353class PortRef(object): 1354 def __init__(self, simobj, name, role): 1355 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1356 self.simobj = simobj 1357 self.name = name 1358 self.role = role 1359 self.peer = None # not associated with another port yet 1360 self.ccConnected = False # C++ port connection done? 1361 self.index = -1 # always -1 for non-vector ports 1362 1363 def __str__(self): 1364 return '%s.%s' % (self.simobj, self.name) 1365 1366 def __len__(self): 1367 # Return the number of connected ports, i.e. 0 is we have no 1368 # peer and 1 if we do. 1369 return int(self.peer != None) 1370 1371 # for config.ini, print peer's name (not ours) 1372 def ini_str(self): 1373 return str(self.peer) 1374 1375 # for config.json 1376 def get_config_as_dict(self): 1377 return {'role' : self.role, 'peer' : str(self.peer)} 1378 1379 def __getattr__(self, attr): 1380 if attr == 'peerObj': 1381 # shorthand for proxies 1382 return self.peer.simobj 1383 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1384 (self.__class__.__name__, attr) 1385 1386 # Full connection is symmetric (both ways). Called via 1387 # SimObject.__setattr__ as a result of a port assignment, e.g., 1388 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1389 # e.g., "obj1.portA[3] = obj2.portB". 1390 def connect(self, other): 1391 if isinstance(other, VectorPortRef): 1392 # reference to plain VectorPort is implicit append 1393 other = other._get_next() 1394 if self.peer and not proxy.isproxy(self.peer): 1395 fatal("Port %s is already connected to %s, cannot connect %s\n", 1396 self, self.peer, other); 1397 self.peer = other 1398 if proxy.isproxy(other): 1399 other.set_param_desc(PortParamDesc()) 1400 elif isinstance(other, PortRef): 1401 if other.peer is not self: 1402 other.connect(self) 1403 else: 1404 raise TypeError, \ 1405 "assigning non-port reference '%s' to port '%s'" \ 1406 % (other, self) 1407 1408 def clone(self, simobj, memo): 1409 if memo.has_key(self): 1410 return memo[self] 1411 newRef = copy.copy(self) 1412 memo[self] = newRef 1413 newRef.simobj = simobj 1414 assert(isSimObject(newRef.simobj)) 1415 if self.peer and not proxy.isproxy(self.peer): 1416 peerObj = self.peer.simobj(_memo=memo) 1417 newRef.peer = self.peer.clone(peerObj, memo) 1418 assert(not isinstance(newRef.peer, VectorPortRef)) 1419 return newRef 1420 1421 def unproxy(self, simobj): 1422 assert(simobj is self.simobj) 1423 if proxy.isproxy(self.peer): 1424 try: 1425 realPeer = self.peer.unproxy(self.simobj) 1426 except: 1427 print "Error in unproxying port '%s' of %s" % \ 1428 (self.name, self.simobj.path()) 1429 raise 1430 self.connect(realPeer) 1431 1432 # Call C++ to create corresponding port connection between C++ objects 1433 def ccConnect(self): 1434 from m5.internal.pyobject import connectPorts 1435 1436 if self.role == 'SLAVE': 1437 # do nothing and let the master take care of it 1438 return 1439 1440 if self.ccConnected: # already done this 1441 return 1442 peer = self.peer 1443 if not self.peer: # nothing to connect to 1444 return 1445 1446 # check that we connect a master to a slave 1447 if self.role == peer.role: 1448 raise TypeError, \ 1449 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1450 % (peer, self, self.role) 1451 1452 try: 1453 # self is always the master and peer the slave 1454 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1455 peer.simobj.getCCObject(), peer.name, peer.index) 1456 except: 1457 print "Error connecting port %s.%s to %s.%s" % \ 1458 (self.simobj.path(), self.name, 1459 peer.simobj.path(), peer.name) 1460 raise 1461 self.ccConnected = True 1462 peer.ccConnected = True 1463 1464# A reference to an individual element of a VectorPort... much like a 1465# PortRef, but has an index. 1466class VectorPortElementRef(PortRef): 1467 def __init__(self, simobj, name, role, index): 1468 PortRef.__init__(self, simobj, name, role) 1469 self.index = index 1470 1471 def __str__(self): 1472 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1473 1474# A reference to a complete vector-valued port (not just a single element). 1475# Can be indexed to retrieve individual VectorPortElementRef instances. 1476class VectorPortRef(object): 1477 def __init__(self, simobj, name, role): 1478 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1479 self.simobj = simobj 1480 self.name = name 1481 self.role = role 1482 self.elements = [] 1483 1484 def __str__(self): 1485 return '%s.%s[:]' % (self.simobj, self.name) 1486 1487 def __len__(self): 1488 # Return the number of connected peers, corresponding the the 1489 # length of the elements. 1490 return len(self.elements) 1491 1492 # for config.ini, print peer's name (not ours) 1493 def ini_str(self): 1494 return ' '.join([el.ini_str() for el in self.elements]) 1495 1496 # for config.json 1497 def get_config_as_dict(self): 1498 return {'role' : self.role, 1499 'peer' : [el.ini_str() for el in self.elements]} 1500 1501 def __getitem__(self, key): 1502 if not isinstance(key, int): 1503 raise TypeError, "VectorPort index must be integer" 1504 if key >= len(self.elements): 1505 # need to extend list 1506 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1507 for i in range(len(self.elements), key+1)] 1508 self.elements.extend(ext) 1509 return self.elements[key] 1510 1511 def _get_next(self): 1512 return self[len(self.elements)] 1513 1514 def __setitem__(self, key, value): 1515 if not isinstance(key, int): 1516 raise TypeError, "VectorPort index must be integer" 1517 self[key].connect(value) 1518 1519 def connect(self, other): 1520 if isinstance(other, (list, tuple)): 1521 # Assign list of port refs to vector port. 1522 # For now, append them... not sure if that's the right semantics 1523 # or if it should replace the current vector. 1524 for ref in other: 1525 self._get_next().connect(ref) 1526 else: 1527 # scalar assignment to plain VectorPort is implicit append 1528 self._get_next().connect(other) 1529 1530 def clone(self, simobj, memo): 1531 if memo.has_key(self): 1532 return memo[self] 1533 newRef = copy.copy(self) 1534 memo[self] = newRef 1535 newRef.simobj = simobj 1536 assert(isSimObject(newRef.simobj)) 1537 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1538 return newRef 1539 1540 def unproxy(self, simobj): 1541 [el.unproxy(simobj) for el in self.elements] 1542 1543 def ccConnect(self): 1544 [el.ccConnect() for el in self.elements] 1545 1546# Port description object. Like a ParamDesc object, this represents a 1547# logical port in the SimObject class, not a particular port on a 1548# SimObject instance. The latter are represented by PortRef objects. 1549class Port(object): 1550 # Generate a PortRef for this port on the given SimObject with the 1551 # given name 1552 def makeRef(self, simobj): 1553 return PortRef(simobj, self.name, self.role) 1554 1555 # Connect an instance of this port (on the given SimObject with 1556 # the given name) with the port described by the supplied PortRef 1557 def connect(self, simobj, ref): 1558 self.makeRef(simobj).connect(ref) 1559 1560 # No need for any pre-declarations at the moment as we merely rely 1561 # on an unsigned int. 1562 def cxx_predecls(self, code): 1563 pass 1564 1565 # Declare an unsigned int with the same name as the port, that 1566 # will eventually hold the number of connected ports (and thus the 1567 # number of elements for a VectorPort). 1568 def cxx_decl(self, code): 1569 code('unsigned int port_${{self.name}}_connection_count;') 1570 1571class MasterPort(Port): 1572 # MasterPort("description") 1573 def __init__(self, *args): 1574 if len(args) == 1: 1575 self.desc = args[0] 1576 self.role = 'MASTER' 1577 else: 1578 raise TypeError, 'wrong number of arguments' 1579 1580class SlavePort(Port): 1581 # SlavePort("description") 1582 def __init__(self, *args): 1583 if len(args) == 1: 1584 self.desc = args[0] 1585 self.role = 'SLAVE' 1586 else: 1587 raise TypeError, 'wrong number of arguments' 1588 1589# VectorPort description object. Like Port, but represents a vector 1590# of connections (e.g., as on a Bus). 1591class VectorPort(Port): 1592 def __init__(self, *args): 1593 self.isVec = True 1594 1595 def makeRef(self, simobj): 1596 return VectorPortRef(simobj, self.name, self.role) 1597 1598class VectorMasterPort(VectorPort): 1599 # VectorMasterPort("description") 1600 def __init__(self, *args): 1601 if len(args) == 1: 1602 self.desc = args[0] 1603 self.role = 'MASTER' 1604 VectorPort.__init__(self, *args) 1605 else: 1606 raise TypeError, 'wrong number of arguments' 1607 1608class VectorSlavePort(VectorPort): 1609 # VectorSlavePort("description") 1610 def __init__(self, *args): 1611 if len(args) == 1: 1612 self.desc = args[0] 1613 self.role = 'SLAVE' 1614 VectorPort.__init__(self, *args) 1615 else: 1616 raise TypeError, 'wrong number of arguments' 1617 1618# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1619# proxy objects (via set_param_desc()) so that proxy error messages 1620# make sense. 1621class PortParamDesc(object): 1622 __metaclass__ = Singleton 1623 1624 ptype_str = 'Port' 1625 ptype = Port 1626 1627baseEnums = allEnums.copy() 1628baseParams = allParams.copy() 1629 1630def clear(): 1631 global allEnums, allParams 1632 1633 allEnums = baseEnums.copy() 1634 allParams = baseParams.copy() 1635 1636__all__ = ['Param', 'VectorParam', 1637 'Enum', 'Bool', 'String', 'Float', 1638 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1639 'Int32', 'UInt32', 'Int64', 'UInt64', 1640 'Counter', 'Addr', 'Tick', 'Percent', 1641 'TcpPort', 'UdpPort', 'EthernetAddr', 1642 'IpAddress', 'IpNetmask', 'IpWithPort', 1643 'MemorySize', 'MemorySize32', 1644 'Latency', 'Frequency', 'Clock', 1645 'NetworkBandwidth', 'MemoryBandwidth', 1646 'Range', 'AddrRange', 'TickRange', 1647 'MaxAddr', 'MaxTick', 'AllMemory', 1648 'Time', 1649 'NextEthernetAddr', 'NULL', 1650 'MasterPort', 'SlavePort', 1651 'VectorMasterPort', 'VectorSlavePort'] 1652 1653import SimObject
|