params.py (13663:9b64aeabf9a5) params.py (13675:afeab32b3655)
1# Copyright (c) 2012-2014, 2017, 2018 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
62from __future__ import print_function
63
64import copy
65import datetime
66import re
67import sys
68import time
69import math
70
71import proxy
72import ticks
73from util import *
74
75def isSimObject(*args, **kwargs):
76 return SimObject.isSimObject(*args, **kwargs)
77
78def isSimObjectSequence(*args, **kwargs):
79 return SimObject.isSimObjectSequence(*args, **kwargs)
80
81def isSimObjectClass(*args, **kwargs):
82 return SimObject.isSimObjectClass(*args, **kwargs)
83
84allParams = {}
85
86class MetaParamValue(type):
87 def __new__(mcls, name, bases, dct):
88 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
89 assert name not in allParams
90 allParams[name] = cls
91 return cls
92
93
94# Dummy base class to identify types that are legitimate for SimObject
95# parameters.
96class ParamValue(object):
97 __metaclass__ = MetaParamValue
98 cmd_line_settable = False
99
100 # Generate the code needed as a prerequisite for declaring a C++
101 # object of this type. Typically generates one or more #include
102 # statements. Used when declaring parameters of this type.
103 @classmethod
104 def cxx_predecls(cls, code):
105 pass
106
107 @classmethod
108 def pybind_predecls(cls, code):
109 cls.cxx_predecls(code)
110
111 # default for printing to .ini file is regular string conversion.
112 # will be overridden in some cases
113 def ini_str(self):
114 return str(self)
115
116 # default for printing to .json file is regular string conversion.
117 # will be overridden in some cases, mostly to use native Python
118 # types where there are similar JSON types
119 def config_value(self):
120 return str(self)
121
122 # Prerequisites for .ini parsing with cxx_ini_parse
123 @classmethod
124 def cxx_ini_predecls(cls, code):
125 pass
126
127 # parse a .ini file entry for this param from string expression
128 # src into lvalue dest (of the param's C++ type)
129 @classmethod
130 def cxx_ini_parse(cls, code, src, dest, ret):
131 code('// Unhandled param type: %s' % cls.__name__)
132 code('%s false;' % ret)
133
134 # allows us to blithely call unproxy() on things without checking
135 # if they're really proxies or not
136 def unproxy(self, base):
137 return self
138
139 # Produce a human readable version of the stored value
140 def pretty_print(self, value):
141 return str(value)
142
143# Regular parameter description.
144class ParamDesc(object):
145 def __init__(self, ptype_str, ptype, *args, **kwargs):
146 self.ptype_str = ptype_str
147 # remember ptype only if it is provided
148 if ptype != None:
149 self.ptype = ptype
150
151 if args:
152 if len(args) == 1:
153 self.desc = args[0]
154 elif len(args) == 2:
155 self.default = args[0]
156 self.desc = args[1]
157 else:
158 raise TypeError('too many arguments')
159
1# Copyright (c) 2012-2014, 2017, 2018 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
62from __future__ import print_function
63
64import copy
65import datetime
66import re
67import sys
68import time
69import math
70
71import proxy
72import ticks
73from util import *
74
75def isSimObject(*args, **kwargs):
76 return SimObject.isSimObject(*args, **kwargs)
77
78def isSimObjectSequence(*args, **kwargs):
79 return SimObject.isSimObjectSequence(*args, **kwargs)
80
81def isSimObjectClass(*args, **kwargs):
82 return SimObject.isSimObjectClass(*args, **kwargs)
83
84allParams = {}
85
86class MetaParamValue(type):
87 def __new__(mcls, name, bases, dct):
88 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
89 assert name not in allParams
90 allParams[name] = cls
91 return cls
92
93
94# Dummy base class to identify types that are legitimate for SimObject
95# parameters.
96class ParamValue(object):
97 __metaclass__ = MetaParamValue
98 cmd_line_settable = False
99
100 # Generate the code needed as a prerequisite for declaring a C++
101 # object of this type. Typically generates one or more #include
102 # statements. Used when declaring parameters of this type.
103 @classmethod
104 def cxx_predecls(cls, code):
105 pass
106
107 @classmethod
108 def pybind_predecls(cls, code):
109 cls.cxx_predecls(code)
110
111 # default for printing to .ini file is regular string conversion.
112 # will be overridden in some cases
113 def ini_str(self):
114 return str(self)
115
116 # default for printing to .json file is regular string conversion.
117 # will be overridden in some cases, mostly to use native Python
118 # types where there are similar JSON types
119 def config_value(self):
120 return str(self)
121
122 # Prerequisites for .ini parsing with cxx_ini_parse
123 @classmethod
124 def cxx_ini_predecls(cls, code):
125 pass
126
127 # parse a .ini file entry for this param from string expression
128 # src into lvalue dest (of the param's C++ type)
129 @classmethod
130 def cxx_ini_parse(cls, code, src, dest, ret):
131 code('// Unhandled param type: %s' % cls.__name__)
132 code('%s false;' % ret)
133
134 # allows us to blithely call unproxy() on things without checking
135 # if they're really proxies or not
136 def unproxy(self, base):
137 return self
138
139 # Produce a human readable version of the stored value
140 def pretty_print(self, value):
141 return str(value)
142
143# Regular parameter description.
144class ParamDesc(object):
145 def __init__(self, ptype_str, ptype, *args, **kwargs):
146 self.ptype_str = ptype_str
147 # remember ptype only if it is provided
148 if ptype != None:
149 self.ptype = ptype
150
151 if args:
152 if len(args) == 1:
153 self.desc = args[0]
154 elif len(args) == 2:
155 self.default = args[0]
156 self.desc = args[1]
157 else:
158 raise TypeError('too many arguments')
159
160 if kwargs.has_key('desc'):
160 if 'desc' in kwargs:
161 assert(not hasattr(self, 'desc'))
162 self.desc = kwargs['desc']
163 del kwargs['desc']
164
161 assert(not hasattr(self, 'desc'))
162 self.desc = kwargs['desc']
163 del kwargs['desc']
164
165 if kwargs.has_key('default'):
165 if 'default' in kwargs:
166 assert(not hasattr(self, 'default'))
167 self.default = kwargs['default']
168 del kwargs['default']
169
170 if kwargs:
171 raise TypeError('extra unknown kwargs %s' % kwargs)
172
173 if not hasattr(self, 'desc'):
174 raise TypeError('desc attribute missing')
175
176 def __getattr__(self, attr):
177 if attr == 'ptype':
178 ptype = SimObject.allClasses[self.ptype_str]
179 assert isSimObjectClass(ptype)
180 self.ptype = ptype
181 return ptype
182
183 raise AttributeError("'%s' object has no attribute '%s'" % \
184 (type(self).__name__, attr))
185
186 def example_str(self):
187 if hasattr(self.ptype, "ex_str"):
188 return self.ptype.ex_str
189 else:
190 return self.ptype_str
191
192 # Is the param available to be exposed on the command line
193 def isCmdLineSettable(self):
194 if hasattr(self.ptype, "cmd_line_settable"):
195 return self.ptype.cmd_line_settable
196 else:
197 return False
198
199 def convert(self, value):
200 if isinstance(value, proxy.BaseProxy):
201 value.set_param_desc(self)
202 return value
203 if not hasattr(self, 'ptype') and isNullPointer(value):
204 # deferred evaluation of SimObject; continue to defer if
205 # we're just assigning a null pointer
206 return value
207 if isinstance(value, self.ptype):
208 return value
209 if isNullPointer(value) and isSimObjectClass(self.ptype):
210 return value
211 return self.ptype(value)
212
213 def pretty_print(self, value):
214 if isinstance(value, proxy.BaseProxy):
215 return str(value)
216 if isNullPointer(value):
217 return NULL
218 return self.ptype(value).pretty_print(value)
219
220 def cxx_predecls(self, code):
221 code('#include <cstddef>')
222 self.ptype.cxx_predecls(code)
223
224 def pybind_predecls(self, code):
225 self.ptype.pybind_predecls(code)
226
227 def cxx_decl(self, code):
228 code('${{self.ptype.cxx_type}} ${{self.name}};')
229
230# Vector-valued parameter description. Just like ParamDesc, except
231# that the value is a vector (list) of the specified type instead of a
232# single value.
233
234class VectorParamValue(list):
235 __metaclass__ = MetaParamValue
236 def __setattr__(self, attr, value):
237 raise AttributeError("Not allowed to set %s on '%s'" % \
238 (attr, type(self).__name__))
239
240 def config_value(self):
241 return [v.config_value() for v in self]
242
243 def ini_str(self):
244 return ' '.join([v.ini_str() for v in self])
245
246 def getValue(self):
247 return [ v.getValue() for v in self ]
248
249 def unproxy(self, base):
250 if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
251 # The value is a proxy (e.g. Parent.any, Parent.all or
252 # Parent.x) therefore try resolve it
253 return self[0].unproxy(base)
254 else:
255 return [v.unproxy(base) for v in self]
256
257class SimObjectVector(VectorParamValue):
258 # support clone operation
259 def __call__(self, **kwargs):
260 return SimObjectVector([v(**kwargs) for v in self])
261
262 def clear_parent(self, old_parent):
263 for v in self:
264 v.clear_parent(old_parent)
265
266 def set_parent(self, parent, name):
267 if len(self) == 1:
268 self[0].set_parent(parent, name)
269 else:
270 width = int(math.ceil(math.log(len(self))/math.log(10)))
271 for i,v in enumerate(self):
272 v.set_parent(parent, "%s%0*d" % (name, width, i))
273
274 def has_parent(self):
275 return any([e.has_parent() for e in self if not isNullPointer(e)])
276
277 # return 'cpu0 cpu1' etc. for print_ini()
278 def get_name(self):
279 return ' '.join([v._name for v in self])
280
281 # By iterating through the constituent members of the vector here
282 # we can nicely handle iterating over all a SimObject's children
283 # without having to provide lots of special functions on
284 # SimObjectVector directly.
285 def descendants(self):
286 for v in self:
287 for obj in v.descendants():
288 yield obj
289
290 def get_config_as_dict(self):
291 a = []
292 for v in self:
293 a.append(v.get_config_as_dict())
294 return a
295
296 # If we are replacing an item in the vector, make sure to set the
297 # parent reference of the new SimObject to be the same as the parent
298 # of the SimObject being replaced. Useful to have if we created
299 # a SimObjectVector of temporary objects that will be modified later in
300 # configuration scripts.
301 def __setitem__(self, key, value):
302 val = self[key]
303 if value.has_parent():
304 warn("SimObject %s already has a parent" % value.get_name() +\
305 " that is being overwritten by a SimObjectVector")
306 value.set_parent(val.get_parent(), val._name)
307 super(SimObjectVector, self).__setitem__(key, value)
308
309 # Enumerate the params of each member of the SimObject vector. Creates
310 # strings that will allow indexing into the vector by the python code and
311 # allow it to be specified on the command line.
312 def enumerateParams(self, flags_dict = {},
313 cmd_line_str = "",
314 access_str = ""):
315 if hasattr(self, "_paramEnumed"):
316 print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
317 else:
318 x = 0
319 for vals in self:
320 # Each entry in the SimObjectVector should be an
321 # instance of a SimObject
322 flags_dict = vals.enumerateParams(flags_dict,
323 cmd_line_str + "%d." % x,
324 access_str + "[%d]." % x)
325 x = x + 1
326
327 return flags_dict
328
329class VectorParamDesc(ParamDesc):
330 # Convert assigned value to appropriate type. If the RHS is not a
331 # list or tuple, it generates a single-element list.
332 def convert(self, value):
333 if isinstance(value, (list, tuple)):
334 # list: coerce each element into new list
335 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
336 elif isinstance(value, str):
337 # If input is a csv string
338 tmp_list = [ ParamDesc.convert(self, v) \
339 for v in value.strip('[').strip(']').split(',') ]
340 else:
341 # singleton: coerce to a single-element list
342 tmp_list = [ ParamDesc.convert(self, value) ]
343
344 if isSimObjectSequence(tmp_list):
345 return SimObjectVector(tmp_list)
346 else:
347 return VectorParamValue(tmp_list)
348
349 # Produce a human readable example string that describes
350 # how to set this vector parameter in the absence of a default
351 # value.
352 def example_str(self):
353 s = super(VectorParamDesc, self).example_str()
354 help_str = "[" + s + "," + s + ", ...]"
355 return help_str
356
357 # Produce a human readable representation of the value of this vector param.
358 def pretty_print(self, value):
359 if isinstance(value, (list, tuple)):
360 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
361 elif isinstance(value, str):
362 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
363 else:
364 tmp_list = [ ParamDesc.pretty_print(self, value) ]
365
366 return tmp_list
367
368 # This is a helper function for the new config system
369 def __call__(self, value):
370 if isinstance(value, (list, tuple)):
371 # list: coerce each element into new list
372 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
373 elif isinstance(value, str):
374 # If input is a csv string
375 tmp_list = [ ParamDesc.convert(self, v) \
376 for v in value.strip('[').strip(']').split(',') ]
377 else:
378 # singleton: coerce to a single-element list
379 tmp_list = [ ParamDesc.convert(self, value) ]
380
381 return VectorParamValue(tmp_list)
382
383 def cxx_predecls(self, code):
384 code('#include <vector>')
385 self.ptype.cxx_predecls(code)
386
387 def pybind_predecls(self, code):
388 code('#include <vector>')
389 self.ptype.pybind_predecls(code)
390
391 def cxx_decl(self, code):
392 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
393
394class ParamFactory(object):
395 def __init__(self, param_desc_class, ptype_str = None):
396 self.param_desc_class = param_desc_class
397 self.ptype_str = ptype_str
398
399 def __getattr__(self, attr):
400 if self.ptype_str:
401 attr = self.ptype_str + '.' + attr
402 return ParamFactory(self.param_desc_class, attr)
403
404 # E.g., Param.Int(5, "number of widgets")
405 def __call__(self, *args, **kwargs):
406 ptype = None
407 try:
408 ptype = allParams[self.ptype_str]
409 except KeyError:
410 # if name isn't defined yet, assume it's a SimObject, and
411 # try to resolve it later
412 pass
413 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
414
415Param = ParamFactory(ParamDesc)
416VectorParam = ParamFactory(VectorParamDesc)
417
418#####################################################################
419#
420# Parameter Types
421#
422# Though native Python types could be used to specify parameter types
423# (the 'ptype' field of the Param and VectorParam classes), it's more
424# flexible to define our own set of types. This gives us more control
425# over how Python expressions are converted to values (via the
426# __init__() constructor) and how these values are printed out (via
427# the __str__() conversion method).
428#
429#####################################################################
430
431# String-valued parameter. Just mixin the ParamValue class with the
432# built-in str class.
433class String(ParamValue,str):
434 cxx_type = 'std::string'
435 cmd_line_settable = True
436
437 @classmethod
438 def cxx_predecls(self, code):
439 code('#include <string>')
440
441 def __call__(self, value):
442 self = value
443 return value
444
445 @classmethod
446 def cxx_ini_parse(self, code, src, dest, ret):
447 code('%s = %s;' % (dest, src))
448 code('%s true;' % ret)
449
450 def getValue(self):
451 return self
452
453# superclass for "numeric" parameter values, to emulate math
454# operations in a type-safe way. e.g., a Latency times an int returns
455# a new Latency object.
456class NumericParamValue(ParamValue):
457 def __str__(self):
458 return str(self.value)
459
460 def __float__(self):
461 return float(self.value)
462
463 def __long__(self):
464 return long(self.value)
465
466 def __int__(self):
467 return int(self.value)
468
469 # hook for bounds checking
470 def _check(self):
471 return
472
473 def __mul__(self, other):
474 newobj = self.__class__(self)
475 newobj.value *= other
476 newobj._check()
477 return newobj
478
479 __rmul__ = __mul__
480
481 def __div__(self, other):
482 newobj = self.__class__(self)
483 newobj.value /= other
484 newobj._check()
485 return newobj
486
487 def __sub__(self, other):
488 newobj = self.__class__(self)
489 newobj.value -= other
490 newobj._check()
491 return newobj
492
493 def config_value(self):
494 return self.value
495
496 @classmethod
497 def cxx_ini_predecls(cls, code):
498 # Assume that base/str.hh will be included anyway
499 # code('#include "base/str.hh"')
500 pass
501
502 # The default for parsing PODs from an .ini entry is to extract from an
503 # istringstream and let overloading choose the right type according to
504 # the dest type.
505 @classmethod
506 def cxx_ini_parse(self, code, src, dest, ret):
507 code('%s to_number(%s, %s);' % (ret, src, dest))
508
509# Metaclass for bounds-checked integer parameters. See CheckedInt.
510class CheckedIntType(MetaParamValue):
511 def __init__(cls, name, bases, dict):
512 super(CheckedIntType, cls).__init__(name, bases, dict)
513
514 # CheckedInt is an abstract base class, so we actually don't
515 # want to do any processing on it... the rest of this code is
516 # just for classes that derive from CheckedInt.
517 if name == 'CheckedInt':
518 return
519
520 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
521 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
522 panic("CheckedInt subclass %s must define either\n" \
523 " 'min' and 'max' or 'size' and 'unsigned'\n",
524 name);
525 if cls.unsigned:
526 cls.min = 0
527 cls.max = 2 ** cls.size - 1
528 else:
529 cls.min = -(2 ** (cls.size - 1))
530 cls.max = (2 ** (cls.size - 1)) - 1
531
532# Abstract superclass for bounds-checked integer parameters. This
533# class is subclassed to generate parameter classes with specific
534# bounds. Initialization of the min and max bounds is done in the
535# metaclass CheckedIntType.__init__.
536class CheckedInt(NumericParamValue):
537 __metaclass__ = CheckedIntType
538 cmd_line_settable = True
539
540 def _check(self):
541 if not self.min <= self.value <= self.max:
542 raise TypeError('Integer param out of bounds %d < %d < %d' % \
543 (self.min, self.value, self.max))
544
545 def __init__(self, value):
546 if isinstance(value, str):
547 self.value = convert.toInteger(value)
548 elif isinstance(value, (int, long, float, NumericParamValue)):
549 self.value = long(value)
550 else:
551 raise TypeError("Can't convert object of type %s to CheckedInt" \
552 % type(value).__name__)
553 self._check()
554
555 def __call__(self, value):
556 self.__init__(value)
557 return value
558
559 @classmethod
560 def cxx_predecls(cls, code):
561 # most derived types require this, so we just do it here once
562 code('#include "base/types.hh"')
563
564 def getValue(self):
565 return long(self.value)
566
567class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
568class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
569
570class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
571class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
572class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
573class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
574class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
575class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
576class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
577class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
578
579class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
580class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
581class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
582class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
583
584class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
585
586class Cycles(CheckedInt):
587 cxx_type = 'Cycles'
588 size = 64
589 unsigned = True
590
591 def getValue(self):
592 from _m5.core import Cycles
593 return Cycles(self.value)
594
595 @classmethod
596 def cxx_ini_predecls(cls, code):
597 # Assume that base/str.hh will be included anyway
598 # code('#include "base/str.hh"')
599 pass
600
601 @classmethod
602 def cxx_ini_parse(cls, code, src, dest, ret):
603 code('uint64_t _temp;')
604 code('bool _ret = to_number(%s, _temp);' % src)
605 code('if (_ret)')
606 code(' %s = Cycles(_temp);' % dest)
607 code('%s _ret;' % ret)
608
609class Float(ParamValue, float):
610 cxx_type = 'double'
611 cmd_line_settable = True
612
613 def __init__(self, value):
614 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
615 self.value = float(value)
616 else:
617 raise TypeError("Can't convert object of type %s to Float" \
618 % type(value).__name__)
619
620 def __call__(self, value):
621 self.__init__(value)
622 return value
623
624 def getValue(self):
625 return float(self.value)
626
627 def config_value(self):
628 return self
629
630 @classmethod
631 def cxx_ini_predecls(cls, code):
632 code('#include <sstream>')
633
634 @classmethod
635 def cxx_ini_parse(self, code, src, dest, ret):
636 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
637
638class MemorySize(CheckedInt):
639 cxx_type = 'uint64_t'
640 ex_str = '512MB'
641 size = 64
642 unsigned = True
643 def __init__(self, value):
644 if isinstance(value, MemorySize):
645 self.value = value.value
646 else:
647 self.value = convert.toMemorySize(value)
648 self._check()
649
650class MemorySize32(CheckedInt):
651 cxx_type = 'uint32_t'
652 ex_str = '512MB'
653 size = 32
654 unsigned = True
655 def __init__(self, value):
656 if isinstance(value, MemorySize):
657 self.value = value.value
658 else:
659 self.value = convert.toMemorySize(value)
660 self._check()
661
662class Addr(CheckedInt):
663 cxx_type = 'Addr'
664 size = 64
665 unsigned = True
666 def __init__(self, value):
667 if isinstance(value, Addr):
668 self.value = value.value
669 else:
670 try:
671 # Often addresses are referred to with sizes. Ex: A device
672 # base address is at "512MB". Use toMemorySize() to convert
673 # these into addresses. If the address is not specified with a
674 # "size", an exception will occur and numeric translation will
675 # proceed below.
676 self.value = convert.toMemorySize(value)
677 except (TypeError, ValueError):
678 # Convert number to string and use long() to do automatic
679 # base conversion (requires base=0 for auto-conversion)
680 self.value = long(str(value), base=0)
681
682 self._check()
683 def __add__(self, other):
684 if isinstance(other, Addr):
685 return self.value + other.value
686 else:
687 return self.value + other
688 def pretty_print(self, value):
689 try:
690 val = convert.toMemorySize(value)
691 except TypeError:
692 val = long(value)
693 return "0x%x" % long(val)
694
695class AddrRange(ParamValue):
696 cxx_type = 'AddrRange'
697
698 def __init__(self, *args, **kwargs):
699 # Disable interleaving and hashing by default
700 self.intlvHighBit = 0
701 self.xorHighBit = 0
702 self.intlvBits = 0
703 self.intlvMatch = 0
704
705 def handle_kwargs(self, kwargs):
706 # An address range needs to have an upper limit, specified
707 # either explicitly with an end, or as an offset using the
708 # size keyword.
709 if 'end' in kwargs:
710 self.end = Addr(kwargs.pop('end'))
711 elif 'size' in kwargs:
712 self.end = self.start + Addr(kwargs.pop('size')) - 1
713 else:
714 raise TypeError("Either end or size must be specified")
715
716 # Now on to the optional bit
717 if 'intlvHighBit' in kwargs:
718 self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
719 if 'xorHighBit' in kwargs:
720 self.xorHighBit = int(kwargs.pop('xorHighBit'))
721 if 'intlvBits' in kwargs:
722 self.intlvBits = int(kwargs.pop('intlvBits'))
723 if 'intlvMatch' in kwargs:
724 self.intlvMatch = int(kwargs.pop('intlvMatch'))
725
726 if len(args) == 0:
727 self.start = Addr(kwargs.pop('start'))
728 handle_kwargs(self, kwargs)
729
730 elif len(args) == 1:
731 if kwargs:
732 self.start = Addr(args[0])
733 handle_kwargs(self, kwargs)
734 elif isinstance(args[0], (list, tuple)):
735 self.start = Addr(args[0][0])
736 self.end = Addr(args[0][1])
737 else:
738 self.start = Addr(0)
739 self.end = Addr(args[0]) - 1
740
741 elif len(args) == 2:
742 self.start = Addr(args[0])
743 self.end = Addr(args[1])
744 else:
745 raise TypeError("Too many arguments specified")
746
747 if kwargs:
748 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
749
750 def __str__(self):
751 return '%s:%s:%s:%s:%s:%s' \
752 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
753 self.intlvBits, self.intlvMatch)
754
755 def size(self):
756 # Divide the size by the size of the interleaving slice
757 return (long(self.end) - long(self.start) + 1) >> self.intlvBits
758
759 @classmethod
760 def cxx_predecls(cls, code):
761 Addr.cxx_predecls(code)
762 code('#include "base/addr_range.hh"')
763
764 @classmethod
765 def pybind_predecls(cls, code):
766 Addr.pybind_predecls(code)
767 code('#include "base/addr_range.hh"')
768
769 @classmethod
770 def cxx_ini_predecls(cls, code):
771 code('#include <sstream>')
772
773 @classmethod
774 def cxx_ini_parse(cls, code, src, dest, ret):
775 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
776 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
777 code('char _sep;')
778 code('std::istringstream _stream(${src});')
779 code('_stream >> _start;')
780 code('_stream.get(_sep);')
781 code('_stream >> _end;')
782 code('if (!_stream.fail() && !_stream.eof()) {')
783 code(' _stream.get(_sep);')
784 code(' _stream >> _intlvHighBit;')
785 code(' _stream.get(_sep);')
786 code(' _stream >> _xorHighBit;')
787 code(' _stream.get(_sep);')
788 code(' _stream >> _intlvBits;')
789 code(' _stream.get(_sep);')
790 code(' _stream >> _intlvMatch;')
791 code('}')
792 code('bool _ret = !_stream.fail() &&'
793 '_stream.eof() && _sep == \':\';')
794 code('if (_ret)')
795 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
796 _xorHighBit, _intlvBits, _intlvMatch);')
797 code('${ret} _ret;')
798
799 def getValue(self):
800 # Go from the Python class to the wrapped C++ class
801 from _m5.range import AddrRange
802
803 return AddrRange(long(self.start), long(self.end),
804 int(self.intlvHighBit), int(self.xorHighBit),
805 int(self.intlvBits), int(self.intlvMatch))
806
807# Boolean parameter type. Python doesn't let you subclass bool, since
808# it doesn't want to let you create multiple instances of True and
809# False. Thus this is a little more complicated than String.
810class Bool(ParamValue):
811 cxx_type = 'bool'
812 cmd_line_settable = True
813
814 def __init__(self, value):
815 try:
816 self.value = convert.toBool(value)
817 except TypeError:
818 self.value = bool(value)
819
820 def __call__(self, value):
821 self.__init__(value)
822 return value
823
824 def getValue(self):
825 return bool(self.value)
826
827 def __str__(self):
828 return str(self.value)
829
830 # implement truth value testing for Bool parameters so that these params
831 # evaluate correctly during the python configuration phase
832 def __nonzero__(self):
833 return bool(self.value)
834
835 def ini_str(self):
836 if self.value:
837 return 'true'
838 return 'false'
839
840 def config_value(self):
841 return self.value
842
843 @classmethod
844 def cxx_ini_predecls(cls, code):
845 # Assume that base/str.hh will be included anyway
846 # code('#include "base/str.hh"')
847 pass
848
849 @classmethod
850 def cxx_ini_parse(cls, code, src, dest, ret):
851 code('%s to_bool(%s, %s);' % (ret, src, dest))
852
853def IncEthernetAddr(addr, val = 1):
854 bytes = map(lambda x: int(x, 16), addr.split(':'))
855 bytes[5] += val
856 for i in (5, 4, 3, 2, 1):
857 val,rem = divmod(bytes[i], 256)
858 bytes[i] = rem
859 if val == 0:
860 break
861 bytes[i - 1] += val
862 assert(bytes[0] <= 255)
863 return ':'.join(map(lambda x: '%02x' % x, bytes))
864
865_NextEthernetAddr = "00:90:00:00:00:01"
866def NextEthernetAddr():
867 global _NextEthernetAddr
868
869 value = _NextEthernetAddr
870 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
871 return value
872
873class EthernetAddr(ParamValue):
874 cxx_type = 'Net::EthAddr'
875 ex_str = "00:90:00:00:00:01"
876 cmd_line_settable = True
877
878 @classmethod
879 def cxx_predecls(cls, code):
880 code('#include "base/inet.hh"')
881
882 def __init__(self, value):
883 if value == NextEthernetAddr:
884 self.value = value
885 return
886
887 if not isinstance(value, str):
888 raise TypeError("expected an ethernet address and didn't get one")
889
890 bytes = value.split(':')
891 if len(bytes) != 6:
892 raise TypeError('invalid ethernet address %s' % value)
893
894 for byte in bytes:
895 if not 0 <= int(byte, base=16) <= 0xff:
896 raise TypeError('invalid ethernet address %s' % value)
897
898 self.value = value
899
900 def __call__(self, value):
901 self.__init__(value)
902 return value
903
904 def unproxy(self, base):
905 if self.value == NextEthernetAddr:
906 return EthernetAddr(self.value())
907 return self
908
909 def getValue(self):
910 from _m5.net import EthAddr
911 return EthAddr(self.value)
912
913 def __str__(self):
914 return self.value
915
916 def ini_str(self):
917 return self.value
918
919 @classmethod
920 def cxx_ini_parse(self, code, src, dest, ret):
921 code('%s = Net::EthAddr(%s);' % (dest, src))
922 code('%s true;' % ret)
923
924# When initializing an IpAddress, pass in an existing IpAddress, a string of
925# the form "a.b.c.d", or an integer representing an IP.
926class IpAddress(ParamValue):
927 cxx_type = 'Net::IpAddress'
928 ex_str = "127.0.0.1"
929 cmd_line_settable = True
930
931 @classmethod
932 def cxx_predecls(cls, code):
933 code('#include "base/inet.hh"')
934
935 def __init__(self, value):
936 if isinstance(value, IpAddress):
937 self.ip = value.ip
938 else:
939 try:
940 self.ip = convert.toIpAddress(value)
941 except TypeError:
942 self.ip = long(value)
943 self.verifyIp()
944
945 def __call__(self, value):
946 self.__init__(value)
947 return value
948
949 def __str__(self):
950 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
951 return '%d.%d.%d.%d' % tuple(tup)
952
953 def __eq__(self, other):
954 if isinstance(other, IpAddress):
955 return self.ip == other.ip
956 elif isinstance(other, str):
957 try:
958 return self.ip == convert.toIpAddress(other)
959 except:
960 return False
961 else:
962 return self.ip == other
963
964 def __ne__(self, other):
965 return not (self == other)
966
967 def verifyIp(self):
968 if self.ip < 0 or self.ip >= (1 << 32):
969 raise TypeError("invalid ip address %#08x" % self.ip)
970
971 def getValue(self):
972 from _m5.net import IpAddress
973 return IpAddress(self.ip)
974
975# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
976# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
977# positional or keyword arguments.
978class IpNetmask(IpAddress):
979 cxx_type = 'Net::IpNetmask'
980 ex_str = "127.0.0.0/24"
981 cmd_line_settable = True
982
983 @classmethod
984 def cxx_predecls(cls, code):
985 code('#include "base/inet.hh"')
986
987 def __init__(self, *args, **kwargs):
988 def handle_kwarg(self, kwargs, key, elseVal = None):
989 if key in kwargs:
990 setattr(self, key, kwargs.pop(key))
991 elif elseVal:
992 setattr(self, key, elseVal)
993 else:
994 raise TypeError("No value set for %s" % key)
995
996 if len(args) == 0:
997 handle_kwarg(self, kwargs, 'ip')
998 handle_kwarg(self, kwargs, 'netmask')
999
1000 elif len(args) == 1:
1001 if kwargs:
1002 if not 'ip' in kwargs and not 'netmask' in kwargs:
1003 raise TypeError("Invalid arguments")
1004 handle_kwarg(self, kwargs, 'ip', args[0])
1005 handle_kwarg(self, kwargs, 'netmask', args[0])
1006 elif isinstance(args[0], IpNetmask):
1007 self.ip = args[0].ip
1008 self.netmask = args[0].netmask
1009 else:
1010 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1011
1012 elif len(args) == 2:
1013 self.ip = args[0]
1014 self.netmask = args[1]
1015 else:
1016 raise TypeError("Too many arguments specified")
1017
1018 if kwargs:
1019 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1020
1021 self.verify()
1022
1023 def __call__(self, value):
1024 self.__init__(value)
1025 return value
1026
1027 def __str__(self):
1028 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1029
1030 def __eq__(self, other):
1031 if isinstance(other, IpNetmask):
1032 return self.ip == other.ip and self.netmask == other.netmask
1033 elif isinstance(other, str):
1034 try:
1035 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1036 except:
1037 return False
1038 else:
1039 return False
1040
1041 def verify(self):
1042 self.verifyIp()
1043 if self.netmask < 0 or self.netmask > 32:
1044 raise TypeError("invalid netmask %d" % netmask)
1045
1046 def getValue(self):
1047 from _m5.net import IpNetmask
1048 return IpNetmask(self.ip, self.netmask)
1049
1050# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1051# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1052class IpWithPort(IpAddress):
1053 cxx_type = 'Net::IpWithPort'
1054 ex_str = "127.0.0.1:80"
1055 cmd_line_settable = True
1056
1057 @classmethod
1058 def cxx_predecls(cls, code):
1059 code('#include "base/inet.hh"')
1060
1061 def __init__(self, *args, **kwargs):
1062 def handle_kwarg(self, kwargs, key, elseVal = None):
1063 if key in kwargs:
1064 setattr(self, key, kwargs.pop(key))
1065 elif elseVal:
1066 setattr(self, key, elseVal)
1067 else:
1068 raise TypeError("No value set for %s" % key)
1069
1070 if len(args) == 0:
1071 handle_kwarg(self, kwargs, 'ip')
1072 handle_kwarg(self, kwargs, 'port')
1073
1074 elif len(args) == 1:
1075 if kwargs:
1076 if not 'ip' in kwargs and not 'port' in kwargs:
1077 raise TypeError("Invalid arguments")
1078 handle_kwarg(self, kwargs, 'ip', args[0])
1079 handle_kwarg(self, kwargs, 'port', args[0])
1080 elif isinstance(args[0], IpWithPort):
1081 self.ip = args[0].ip
1082 self.port = args[0].port
1083 else:
1084 (self.ip, self.port) = convert.toIpWithPort(args[0])
1085
1086 elif len(args) == 2:
1087 self.ip = args[0]
1088 self.port = args[1]
1089 else:
1090 raise TypeError("Too many arguments specified")
1091
1092 if kwargs:
1093 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1094
1095 self.verify()
1096
1097 def __call__(self, value):
1098 self.__init__(value)
1099 return value
1100
1101 def __str__(self):
1102 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1103
1104 def __eq__(self, other):
1105 if isinstance(other, IpWithPort):
1106 return self.ip == other.ip and self.port == other.port
1107 elif isinstance(other, str):
1108 try:
1109 return (self.ip, self.port) == convert.toIpWithPort(other)
1110 except:
1111 return False
1112 else:
1113 return False
1114
1115 def verify(self):
1116 self.verifyIp()
1117 if self.port < 0 or self.port > 0xffff:
1118 raise TypeError("invalid port %d" % self.port)
1119
1120 def getValue(self):
1121 from _m5.net import IpWithPort
1122 return IpWithPort(self.ip, self.port)
1123
1124time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1125 "%a %b %d %H:%M:%S %Y",
1126 "%Y/%m/%d %H:%M:%S",
1127 "%Y/%m/%d %H:%M",
1128 "%Y/%m/%d",
1129 "%m/%d/%Y %H:%M:%S",
1130 "%m/%d/%Y %H:%M",
1131 "%m/%d/%Y",
1132 "%m/%d/%y %H:%M:%S",
1133 "%m/%d/%y %H:%M",
1134 "%m/%d/%y"]
1135
1136
1137def parse_time(value):
1138 from time import gmtime, strptime, struct_time, time
1139 from datetime import datetime, date
1140
1141 if isinstance(value, struct_time):
1142 return value
1143
1144 if isinstance(value, (int, long)):
1145 return gmtime(value)
1146
1147 if isinstance(value, (datetime, date)):
1148 return value.timetuple()
1149
1150 if isinstance(value, str):
1151 if value in ('Now', 'Today'):
1152 return time.gmtime(time.time())
1153
1154 for format in time_formats:
1155 try:
1156 return strptime(value, format)
1157 except ValueError:
1158 pass
1159
1160 raise ValueError("Could not parse '%s' as a time" % value)
1161
1162class Time(ParamValue):
1163 cxx_type = 'tm'
1164
1165 @classmethod
1166 def cxx_predecls(cls, code):
1167 code('#include <time.h>')
1168
1169 def __init__(self, value):
1170 self.value = parse_time(value)
1171
1172 def __call__(self, value):
1173 self.__init__(value)
1174 return value
1175
1176 def getValue(self):
1177 from _m5.core import tm
1178 import calendar
1179
1180 return tm.gmtime(calendar.timegm(self.value))
1181
1182 def __str__(self):
1183 return time.asctime(self.value)
1184
1185 def ini_str(self):
1186 return str(self)
1187
1188 def get_config_as_dict(self):
1189 assert false
1190 return str(self)
1191
1192 @classmethod
1193 def cxx_ini_predecls(cls, code):
1194 code('#include <time.h>')
1195
1196 @classmethod
1197 def cxx_ini_parse(cls, code, src, dest, ret):
1198 code('char *_parse_ret = strptime((${src}).c_str(),')
1199 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1200 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1201
1202# Enumerated types are a little more complex. The user specifies the
1203# type as Enum(foo) where foo is either a list or dictionary of
1204# alternatives (typically strings, but not necessarily so). (In the
1205# long run, the integer value of the parameter will be the list index
1206# or the corresponding dictionary value. For now, since we only check
1207# that the alternative is valid and then spit it into a .ini file,
1208# there's not much point in using the dictionary.)
1209
1210# What Enum() must do is generate a new type encapsulating the
1211# provided list/dictionary so that specific values of the parameter
1212# can be instances of that type. We define two hidden internal
1213# classes (_ListEnum and _DictEnum) to serve as base classes, then
1214# derive the new type from the appropriate base class on the fly.
1215
1216allEnums = {}
1217# Metaclass for Enum types
1218class MetaEnum(MetaParamValue):
1219 def __new__(mcls, name, bases, dict):
1220 assert name not in allEnums
1221
1222 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1223 allEnums[name] = cls
1224 return cls
1225
1226 def __init__(cls, name, bases, init_dict):
166 assert(not hasattr(self, 'default'))
167 self.default = kwargs['default']
168 del kwargs['default']
169
170 if kwargs:
171 raise TypeError('extra unknown kwargs %s' % kwargs)
172
173 if not hasattr(self, 'desc'):
174 raise TypeError('desc attribute missing')
175
176 def __getattr__(self, attr):
177 if attr == 'ptype':
178 ptype = SimObject.allClasses[self.ptype_str]
179 assert isSimObjectClass(ptype)
180 self.ptype = ptype
181 return ptype
182
183 raise AttributeError("'%s' object has no attribute '%s'" % \
184 (type(self).__name__, attr))
185
186 def example_str(self):
187 if hasattr(self.ptype, "ex_str"):
188 return self.ptype.ex_str
189 else:
190 return self.ptype_str
191
192 # Is the param available to be exposed on the command line
193 def isCmdLineSettable(self):
194 if hasattr(self.ptype, "cmd_line_settable"):
195 return self.ptype.cmd_line_settable
196 else:
197 return False
198
199 def convert(self, value):
200 if isinstance(value, proxy.BaseProxy):
201 value.set_param_desc(self)
202 return value
203 if not hasattr(self, 'ptype') and isNullPointer(value):
204 # deferred evaluation of SimObject; continue to defer if
205 # we're just assigning a null pointer
206 return value
207 if isinstance(value, self.ptype):
208 return value
209 if isNullPointer(value) and isSimObjectClass(self.ptype):
210 return value
211 return self.ptype(value)
212
213 def pretty_print(self, value):
214 if isinstance(value, proxy.BaseProxy):
215 return str(value)
216 if isNullPointer(value):
217 return NULL
218 return self.ptype(value).pretty_print(value)
219
220 def cxx_predecls(self, code):
221 code('#include <cstddef>')
222 self.ptype.cxx_predecls(code)
223
224 def pybind_predecls(self, code):
225 self.ptype.pybind_predecls(code)
226
227 def cxx_decl(self, code):
228 code('${{self.ptype.cxx_type}} ${{self.name}};')
229
230# Vector-valued parameter description. Just like ParamDesc, except
231# that the value is a vector (list) of the specified type instead of a
232# single value.
233
234class VectorParamValue(list):
235 __metaclass__ = MetaParamValue
236 def __setattr__(self, attr, value):
237 raise AttributeError("Not allowed to set %s on '%s'" % \
238 (attr, type(self).__name__))
239
240 def config_value(self):
241 return [v.config_value() for v in self]
242
243 def ini_str(self):
244 return ' '.join([v.ini_str() for v in self])
245
246 def getValue(self):
247 return [ v.getValue() for v in self ]
248
249 def unproxy(self, base):
250 if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
251 # The value is a proxy (e.g. Parent.any, Parent.all or
252 # Parent.x) therefore try resolve it
253 return self[0].unproxy(base)
254 else:
255 return [v.unproxy(base) for v in self]
256
257class SimObjectVector(VectorParamValue):
258 # support clone operation
259 def __call__(self, **kwargs):
260 return SimObjectVector([v(**kwargs) for v in self])
261
262 def clear_parent(self, old_parent):
263 for v in self:
264 v.clear_parent(old_parent)
265
266 def set_parent(self, parent, name):
267 if len(self) == 1:
268 self[0].set_parent(parent, name)
269 else:
270 width = int(math.ceil(math.log(len(self))/math.log(10)))
271 for i,v in enumerate(self):
272 v.set_parent(parent, "%s%0*d" % (name, width, i))
273
274 def has_parent(self):
275 return any([e.has_parent() for e in self if not isNullPointer(e)])
276
277 # return 'cpu0 cpu1' etc. for print_ini()
278 def get_name(self):
279 return ' '.join([v._name for v in self])
280
281 # By iterating through the constituent members of the vector here
282 # we can nicely handle iterating over all a SimObject's children
283 # without having to provide lots of special functions on
284 # SimObjectVector directly.
285 def descendants(self):
286 for v in self:
287 for obj in v.descendants():
288 yield obj
289
290 def get_config_as_dict(self):
291 a = []
292 for v in self:
293 a.append(v.get_config_as_dict())
294 return a
295
296 # If we are replacing an item in the vector, make sure to set the
297 # parent reference of the new SimObject to be the same as the parent
298 # of the SimObject being replaced. Useful to have if we created
299 # a SimObjectVector of temporary objects that will be modified later in
300 # configuration scripts.
301 def __setitem__(self, key, value):
302 val = self[key]
303 if value.has_parent():
304 warn("SimObject %s already has a parent" % value.get_name() +\
305 " that is being overwritten by a SimObjectVector")
306 value.set_parent(val.get_parent(), val._name)
307 super(SimObjectVector, self).__setitem__(key, value)
308
309 # Enumerate the params of each member of the SimObject vector. Creates
310 # strings that will allow indexing into the vector by the python code and
311 # allow it to be specified on the command line.
312 def enumerateParams(self, flags_dict = {},
313 cmd_line_str = "",
314 access_str = ""):
315 if hasattr(self, "_paramEnumed"):
316 print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
317 else:
318 x = 0
319 for vals in self:
320 # Each entry in the SimObjectVector should be an
321 # instance of a SimObject
322 flags_dict = vals.enumerateParams(flags_dict,
323 cmd_line_str + "%d." % x,
324 access_str + "[%d]." % x)
325 x = x + 1
326
327 return flags_dict
328
329class VectorParamDesc(ParamDesc):
330 # Convert assigned value to appropriate type. If the RHS is not a
331 # list or tuple, it generates a single-element list.
332 def convert(self, value):
333 if isinstance(value, (list, tuple)):
334 # list: coerce each element into new list
335 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
336 elif isinstance(value, str):
337 # If input is a csv string
338 tmp_list = [ ParamDesc.convert(self, v) \
339 for v in value.strip('[').strip(']').split(',') ]
340 else:
341 # singleton: coerce to a single-element list
342 tmp_list = [ ParamDesc.convert(self, value) ]
343
344 if isSimObjectSequence(tmp_list):
345 return SimObjectVector(tmp_list)
346 else:
347 return VectorParamValue(tmp_list)
348
349 # Produce a human readable example string that describes
350 # how to set this vector parameter in the absence of a default
351 # value.
352 def example_str(self):
353 s = super(VectorParamDesc, self).example_str()
354 help_str = "[" + s + "," + s + ", ...]"
355 return help_str
356
357 # Produce a human readable representation of the value of this vector param.
358 def pretty_print(self, value):
359 if isinstance(value, (list, tuple)):
360 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
361 elif isinstance(value, str):
362 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
363 else:
364 tmp_list = [ ParamDesc.pretty_print(self, value) ]
365
366 return tmp_list
367
368 # This is a helper function for the new config system
369 def __call__(self, value):
370 if isinstance(value, (list, tuple)):
371 # list: coerce each element into new list
372 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
373 elif isinstance(value, str):
374 # If input is a csv string
375 tmp_list = [ ParamDesc.convert(self, v) \
376 for v in value.strip('[').strip(']').split(',') ]
377 else:
378 # singleton: coerce to a single-element list
379 tmp_list = [ ParamDesc.convert(self, value) ]
380
381 return VectorParamValue(tmp_list)
382
383 def cxx_predecls(self, code):
384 code('#include <vector>')
385 self.ptype.cxx_predecls(code)
386
387 def pybind_predecls(self, code):
388 code('#include <vector>')
389 self.ptype.pybind_predecls(code)
390
391 def cxx_decl(self, code):
392 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
393
394class ParamFactory(object):
395 def __init__(self, param_desc_class, ptype_str = None):
396 self.param_desc_class = param_desc_class
397 self.ptype_str = ptype_str
398
399 def __getattr__(self, attr):
400 if self.ptype_str:
401 attr = self.ptype_str + '.' + attr
402 return ParamFactory(self.param_desc_class, attr)
403
404 # E.g., Param.Int(5, "number of widgets")
405 def __call__(self, *args, **kwargs):
406 ptype = None
407 try:
408 ptype = allParams[self.ptype_str]
409 except KeyError:
410 # if name isn't defined yet, assume it's a SimObject, and
411 # try to resolve it later
412 pass
413 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
414
415Param = ParamFactory(ParamDesc)
416VectorParam = ParamFactory(VectorParamDesc)
417
418#####################################################################
419#
420# Parameter Types
421#
422# Though native Python types could be used to specify parameter types
423# (the 'ptype' field of the Param and VectorParam classes), it's more
424# flexible to define our own set of types. This gives us more control
425# over how Python expressions are converted to values (via the
426# __init__() constructor) and how these values are printed out (via
427# the __str__() conversion method).
428#
429#####################################################################
430
431# String-valued parameter. Just mixin the ParamValue class with the
432# built-in str class.
433class String(ParamValue,str):
434 cxx_type = 'std::string'
435 cmd_line_settable = True
436
437 @classmethod
438 def cxx_predecls(self, code):
439 code('#include <string>')
440
441 def __call__(self, value):
442 self = value
443 return value
444
445 @classmethod
446 def cxx_ini_parse(self, code, src, dest, ret):
447 code('%s = %s;' % (dest, src))
448 code('%s true;' % ret)
449
450 def getValue(self):
451 return self
452
453# superclass for "numeric" parameter values, to emulate math
454# operations in a type-safe way. e.g., a Latency times an int returns
455# a new Latency object.
456class NumericParamValue(ParamValue):
457 def __str__(self):
458 return str(self.value)
459
460 def __float__(self):
461 return float(self.value)
462
463 def __long__(self):
464 return long(self.value)
465
466 def __int__(self):
467 return int(self.value)
468
469 # hook for bounds checking
470 def _check(self):
471 return
472
473 def __mul__(self, other):
474 newobj = self.__class__(self)
475 newobj.value *= other
476 newobj._check()
477 return newobj
478
479 __rmul__ = __mul__
480
481 def __div__(self, other):
482 newobj = self.__class__(self)
483 newobj.value /= other
484 newobj._check()
485 return newobj
486
487 def __sub__(self, other):
488 newobj = self.__class__(self)
489 newobj.value -= other
490 newobj._check()
491 return newobj
492
493 def config_value(self):
494 return self.value
495
496 @classmethod
497 def cxx_ini_predecls(cls, code):
498 # Assume that base/str.hh will be included anyway
499 # code('#include "base/str.hh"')
500 pass
501
502 # The default for parsing PODs from an .ini entry is to extract from an
503 # istringstream and let overloading choose the right type according to
504 # the dest type.
505 @classmethod
506 def cxx_ini_parse(self, code, src, dest, ret):
507 code('%s to_number(%s, %s);' % (ret, src, dest))
508
509# Metaclass for bounds-checked integer parameters. See CheckedInt.
510class CheckedIntType(MetaParamValue):
511 def __init__(cls, name, bases, dict):
512 super(CheckedIntType, cls).__init__(name, bases, dict)
513
514 # CheckedInt is an abstract base class, so we actually don't
515 # want to do any processing on it... the rest of this code is
516 # just for classes that derive from CheckedInt.
517 if name == 'CheckedInt':
518 return
519
520 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
521 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
522 panic("CheckedInt subclass %s must define either\n" \
523 " 'min' and 'max' or 'size' and 'unsigned'\n",
524 name);
525 if cls.unsigned:
526 cls.min = 0
527 cls.max = 2 ** cls.size - 1
528 else:
529 cls.min = -(2 ** (cls.size - 1))
530 cls.max = (2 ** (cls.size - 1)) - 1
531
532# Abstract superclass for bounds-checked integer parameters. This
533# class is subclassed to generate parameter classes with specific
534# bounds. Initialization of the min and max bounds is done in the
535# metaclass CheckedIntType.__init__.
536class CheckedInt(NumericParamValue):
537 __metaclass__ = CheckedIntType
538 cmd_line_settable = True
539
540 def _check(self):
541 if not self.min <= self.value <= self.max:
542 raise TypeError('Integer param out of bounds %d < %d < %d' % \
543 (self.min, self.value, self.max))
544
545 def __init__(self, value):
546 if isinstance(value, str):
547 self.value = convert.toInteger(value)
548 elif isinstance(value, (int, long, float, NumericParamValue)):
549 self.value = long(value)
550 else:
551 raise TypeError("Can't convert object of type %s to CheckedInt" \
552 % type(value).__name__)
553 self._check()
554
555 def __call__(self, value):
556 self.__init__(value)
557 return value
558
559 @classmethod
560 def cxx_predecls(cls, code):
561 # most derived types require this, so we just do it here once
562 code('#include "base/types.hh"')
563
564 def getValue(self):
565 return long(self.value)
566
567class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
568class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
569
570class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
571class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
572class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
573class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
574class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
575class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
576class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
577class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
578
579class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
580class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
581class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
582class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
583
584class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
585
586class Cycles(CheckedInt):
587 cxx_type = 'Cycles'
588 size = 64
589 unsigned = True
590
591 def getValue(self):
592 from _m5.core import Cycles
593 return Cycles(self.value)
594
595 @classmethod
596 def cxx_ini_predecls(cls, code):
597 # Assume that base/str.hh will be included anyway
598 # code('#include "base/str.hh"')
599 pass
600
601 @classmethod
602 def cxx_ini_parse(cls, code, src, dest, ret):
603 code('uint64_t _temp;')
604 code('bool _ret = to_number(%s, _temp);' % src)
605 code('if (_ret)')
606 code(' %s = Cycles(_temp);' % dest)
607 code('%s _ret;' % ret)
608
609class Float(ParamValue, float):
610 cxx_type = 'double'
611 cmd_line_settable = True
612
613 def __init__(self, value):
614 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
615 self.value = float(value)
616 else:
617 raise TypeError("Can't convert object of type %s to Float" \
618 % type(value).__name__)
619
620 def __call__(self, value):
621 self.__init__(value)
622 return value
623
624 def getValue(self):
625 return float(self.value)
626
627 def config_value(self):
628 return self
629
630 @classmethod
631 def cxx_ini_predecls(cls, code):
632 code('#include <sstream>')
633
634 @classmethod
635 def cxx_ini_parse(self, code, src, dest, ret):
636 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
637
638class MemorySize(CheckedInt):
639 cxx_type = 'uint64_t'
640 ex_str = '512MB'
641 size = 64
642 unsigned = True
643 def __init__(self, value):
644 if isinstance(value, MemorySize):
645 self.value = value.value
646 else:
647 self.value = convert.toMemorySize(value)
648 self._check()
649
650class MemorySize32(CheckedInt):
651 cxx_type = 'uint32_t'
652 ex_str = '512MB'
653 size = 32
654 unsigned = True
655 def __init__(self, value):
656 if isinstance(value, MemorySize):
657 self.value = value.value
658 else:
659 self.value = convert.toMemorySize(value)
660 self._check()
661
662class Addr(CheckedInt):
663 cxx_type = 'Addr'
664 size = 64
665 unsigned = True
666 def __init__(self, value):
667 if isinstance(value, Addr):
668 self.value = value.value
669 else:
670 try:
671 # Often addresses are referred to with sizes. Ex: A device
672 # base address is at "512MB". Use toMemorySize() to convert
673 # these into addresses. If the address is not specified with a
674 # "size", an exception will occur and numeric translation will
675 # proceed below.
676 self.value = convert.toMemorySize(value)
677 except (TypeError, ValueError):
678 # Convert number to string and use long() to do automatic
679 # base conversion (requires base=0 for auto-conversion)
680 self.value = long(str(value), base=0)
681
682 self._check()
683 def __add__(self, other):
684 if isinstance(other, Addr):
685 return self.value + other.value
686 else:
687 return self.value + other
688 def pretty_print(self, value):
689 try:
690 val = convert.toMemorySize(value)
691 except TypeError:
692 val = long(value)
693 return "0x%x" % long(val)
694
695class AddrRange(ParamValue):
696 cxx_type = 'AddrRange'
697
698 def __init__(self, *args, **kwargs):
699 # Disable interleaving and hashing by default
700 self.intlvHighBit = 0
701 self.xorHighBit = 0
702 self.intlvBits = 0
703 self.intlvMatch = 0
704
705 def handle_kwargs(self, kwargs):
706 # An address range needs to have an upper limit, specified
707 # either explicitly with an end, or as an offset using the
708 # size keyword.
709 if 'end' in kwargs:
710 self.end = Addr(kwargs.pop('end'))
711 elif 'size' in kwargs:
712 self.end = self.start + Addr(kwargs.pop('size')) - 1
713 else:
714 raise TypeError("Either end or size must be specified")
715
716 # Now on to the optional bit
717 if 'intlvHighBit' in kwargs:
718 self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
719 if 'xorHighBit' in kwargs:
720 self.xorHighBit = int(kwargs.pop('xorHighBit'))
721 if 'intlvBits' in kwargs:
722 self.intlvBits = int(kwargs.pop('intlvBits'))
723 if 'intlvMatch' in kwargs:
724 self.intlvMatch = int(kwargs.pop('intlvMatch'))
725
726 if len(args) == 0:
727 self.start = Addr(kwargs.pop('start'))
728 handle_kwargs(self, kwargs)
729
730 elif len(args) == 1:
731 if kwargs:
732 self.start = Addr(args[0])
733 handle_kwargs(self, kwargs)
734 elif isinstance(args[0], (list, tuple)):
735 self.start = Addr(args[0][0])
736 self.end = Addr(args[0][1])
737 else:
738 self.start = Addr(0)
739 self.end = Addr(args[0]) - 1
740
741 elif len(args) == 2:
742 self.start = Addr(args[0])
743 self.end = Addr(args[1])
744 else:
745 raise TypeError("Too many arguments specified")
746
747 if kwargs:
748 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
749
750 def __str__(self):
751 return '%s:%s:%s:%s:%s:%s' \
752 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
753 self.intlvBits, self.intlvMatch)
754
755 def size(self):
756 # Divide the size by the size of the interleaving slice
757 return (long(self.end) - long(self.start) + 1) >> self.intlvBits
758
759 @classmethod
760 def cxx_predecls(cls, code):
761 Addr.cxx_predecls(code)
762 code('#include "base/addr_range.hh"')
763
764 @classmethod
765 def pybind_predecls(cls, code):
766 Addr.pybind_predecls(code)
767 code('#include "base/addr_range.hh"')
768
769 @classmethod
770 def cxx_ini_predecls(cls, code):
771 code('#include <sstream>')
772
773 @classmethod
774 def cxx_ini_parse(cls, code, src, dest, ret):
775 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
776 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
777 code('char _sep;')
778 code('std::istringstream _stream(${src});')
779 code('_stream >> _start;')
780 code('_stream.get(_sep);')
781 code('_stream >> _end;')
782 code('if (!_stream.fail() && !_stream.eof()) {')
783 code(' _stream.get(_sep);')
784 code(' _stream >> _intlvHighBit;')
785 code(' _stream.get(_sep);')
786 code(' _stream >> _xorHighBit;')
787 code(' _stream.get(_sep);')
788 code(' _stream >> _intlvBits;')
789 code(' _stream.get(_sep);')
790 code(' _stream >> _intlvMatch;')
791 code('}')
792 code('bool _ret = !_stream.fail() &&'
793 '_stream.eof() && _sep == \':\';')
794 code('if (_ret)')
795 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
796 _xorHighBit, _intlvBits, _intlvMatch);')
797 code('${ret} _ret;')
798
799 def getValue(self):
800 # Go from the Python class to the wrapped C++ class
801 from _m5.range import AddrRange
802
803 return AddrRange(long(self.start), long(self.end),
804 int(self.intlvHighBit), int(self.xorHighBit),
805 int(self.intlvBits), int(self.intlvMatch))
806
807# Boolean parameter type. Python doesn't let you subclass bool, since
808# it doesn't want to let you create multiple instances of True and
809# False. Thus this is a little more complicated than String.
810class Bool(ParamValue):
811 cxx_type = 'bool'
812 cmd_line_settable = True
813
814 def __init__(self, value):
815 try:
816 self.value = convert.toBool(value)
817 except TypeError:
818 self.value = bool(value)
819
820 def __call__(self, value):
821 self.__init__(value)
822 return value
823
824 def getValue(self):
825 return bool(self.value)
826
827 def __str__(self):
828 return str(self.value)
829
830 # implement truth value testing for Bool parameters so that these params
831 # evaluate correctly during the python configuration phase
832 def __nonzero__(self):
833 return bool(self.value)
834
835 def ini_str(self):
836 if self.value:
837 return 'true'
838 return 'false'
839
840 def config_value(self):
841 return self.value
842
843 @classmethod
844 def cxx_ini_predecls(cls, code):
845 # Assume that base/str.hh will be included anyway
846 # code('#include "base/str.hh"')
847 pass
848
849 @classmethod
850 def cxx_ini_parse(cls, code, src, dest, ret):
851 code('%s to_bool(%s, %s);' % (ret, src, dest))
852
853def IncEthernetAddr(addr, val = 1):
854 bytes = map(lambda x: int(x, 16), addr.split(':'))
855 bytes[5] += val
856 for i in (5, 4, 3, 2, 1):
857 val,rem = divmod(bytes[i], 256)
858 bytes[i] = rem
859 if val == 0:
860 break
861 bytes[i - 1] += val
862 assert(bytes[0] <= 255)
863 return ':'.join(map(lambda x: '%02x' % x, bytes))
864
865_NextEthernetAddr = "00:90:00:00:00:01"
866def NextEthernetAddr():
867 global _NextEthernetAddr
868
869 value = _NextEthernetAddr
870 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
871 return value
872
873class EthernetAddr(ParamValue):
874 cxx_type = 'Net::EthAddr'
875 ex_str = "00:90:00:00:00:01"
876 cmd_line_settable = True
877
878 @classmethod
879 def cxx_predecls(cls, code):
880 code('#include "base/inet.hh"')
881
882 def __init__(self, value):
883 if value == NextEthernetAddr:
884 self.value = value
885 return
886
887 if not isinstance(value, str):
888 raise TypeError("expected an ethernet address and didn't get one")
889
890 bytes = value.split(':')
891 if len(bytes) != 6:
892 raise TypeError('invalid ethernet address %s' % value)
893
894 for byte in bytes:
895 if not 0 <= int(byte, base=16) <= 0xff:
896 raise TypeError('invalid ethernet address %s' % value)
897
898 self.value = value
899
900 def __call__(self, value):
901 self.__init__(value)
902 return value
903
904 def unproxy(self, base):
905 if self.value == NextEthernetAddr:
906 return EthernetAddr(self.value())
907 return self
908
909 def getValue(self):
910 from _m5.net import EthAddr
911 return EthAddr(self.value)
912
913 def __str__(self):
914 return self.value
915
916 def ini_str(self):
917 return self.value
918
919 @classmethod
920 def cxx_ini_parse(self, code, src, dest, ret):
921 code('%s = Net::EthAddr(%s);' % (dest, src))
922 code('%s true;' % ret)
923
924# When initializing an IpAddress, pass in an existing IpAddress, a string of
925# the form "a.b.c.d", or an integer representing an IP.
926class IpAddress(ParamValue):
927 cxx_type = 'Net::IpAddress'
928 ex_str = "127.0.0.1"
929 cmd_line_settable = True
930
931 @classmethod
932 def cxx_predecls(cls, code):
933 code('#include "base/inet.hh"')
934
935 def __init__(self, value):
936 if isinstance(value, IpAddress):
937 self.ip = value.ip
938 else:
939 try:
940 self.ip = convert.toIpAddress(value)
941 except TypeError:
942 self.ip = long(value)
943 self.verifyIp()
944
945 def __call__(self, value):
946 self.__init__(value)
947 return value
948
949 def __str__(self):
950 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
951 return '%d.%d.%d.%d' % tuple(tup)
952
953 def __eq__(self, other):
954 if isinstance(other, IpAddress):
955 return self.ip == other.ip
956 elif isinstance(other, str):
957 try:
958 return self.ip == convert.toIpAddress(other)
959 except:
960 return False
961 else:
962 return self.ip == other
963
964 def __ne__(self, other):
965 return not (self == other)
966
967 def verifyIp(self):
968 if self.ip < 0 or self.ip >= (1 << 32):
969 raise TypeError("invalid ip address %#08x" % self.ip)
970
971 def getValue(self):
972 from _m5.net import IpAddress
973 return IpAddress(self.ip)
974
975# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
976# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
977# positional or keyword arguments.
978class IpNetmask(IpAddress):
979 cxx_type = 'Net::IpNetmask'
980 ex_str = "127.0.0.0/24"
981 cmd_line_settable = True
982
983 @classmethod
984 def cxx_predecls(cls, code):
985 code('#include "base/inet.hh"')
986
987 def __init__(self, *args, **kwargs):
988 def handle_kwarg(self, kwargs, key, elseVal = None):
989 if key in kwargs:
990 setattr(self, key, kwargs.pop(key))
991 elif elseVal:
992 setattr(self, key, elseVal)
993 else:
994 raise TypeError("No value set for %s" % key)
995
996 if len(args) == 0:
997 handle_kwarg(self, kwargs, 'ip')
998 handle_kwarg(self, kwargs, 'netmask')
999
1000 elif len(args) == 1:
1001 if kwargs:
1002 if not 'ip' in kwargs and not 'netmask' in kwargs:
1003 raise TypeError("Invalid arguments")
1004 handle_kwarg(self, kwargs, 'ip', args[0])
1005 handle_kwarg(self, kwargs, 'netmask', args[0])
1006 elif isinstance(args[0], IpNetmask):
1007 self.ip = args[0].ip
1008 self.netmask = args[0].netmask
1009 else:
1010 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1011
1012 elif len(args) == 2:
1013 self.ip = args[0]
1014 self.netmask = args[1]
1015 else:
1016 raise TypeError("Too many arguments specified")
1017
1018 if kwargs:
1019 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1020
1021 self.verify()
1022
1023 def __call__(self, value):
1024 self.__init__(value)
1025 return value
1026
1027 def __str__(self):
1028 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1029
1030 def __eq__(self, other):
1031 if isinstance(other, IpNetmask):
1032 return self.ip == other.ip and self.netmask == other.netmask
1033 elif isinstance(other, str):
1034 try:
1035 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1036 except:
1037 return False
1038 else:
1039 return False
1040
1041 def verify(self):
1042 self.verifyIp()
1043 if self.netmask < 0 or self.netmask > 32:
1044 raise TypeError("invalid netmask %d" % netmask)
1045
1046 def getValue(self):
1047 from _m5.net import IpNetmask
1048 return IpNetmask(self.ip, self.netmask)
1049
1050# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1051# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1052class IpWithPort(IpAddress):
1053 cxx_type = 'Net::IpWithPort'
1054 ex_str = "127.0.0.1:80"
1055 cmd_line_settable = True
1056
1057 @classmethod
1058 def cxx_predecls(cls, code):
1059 code('#include "base/inet.hh"')
1060
1061 def __init__(self, *args, **kwargs):
1062 def handle_kwarg(self, kwargs, key, elseVal = None):
1063 if key in kwargs:
1064 setattr(self, key, kwargs.pop(key))
1065 elif elseVal:
1066 setattr(self, key, elseVal)
1067 else:
1068 raise TypeError("No value set for %s" % key)
1069
1070 if len(args) == 0:
1071 handle_kwarg(self, kwargs, 'ip')
1072 handle_kwarg(self, kwargs, 'port')
1073
1074 elif len(args) == 1:
1075 if kwargs:
1076 if not 'ip' in kwargs and not 'port' in kwargs:
1077 raise TypeError("Invalid arguments")
1078 handle_kwarg(self, kwargs, 'ip', args[0])
1079 handle_kwarg(self, kwargs, 'port', args[0])
1080 elif isinstance(args[0], IpWithPort):
1081 self.ip = args[0].ip
1082 self.port = args[0].port
1083 else:
1084 (self.ip, self.port) = convert.toIpWithPort(args[0])
1085
1086 elif len(args) == 2:
1087 self.ip = args[0]
1088 self.port = args[1]
1089 else:
1090 raise TypeError("Too many arguments specified")
1091
1092 if kwargs:
1093 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1094
1095 self.verify()
1096
1097 def __call__(self, value):
1098 self.__init__(value)
1099 return value
1100
1101 def __str__(self):
1102 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1103
1104 def __eq__(self, other):
1105 if isinstance(other, IpWithPort):
1106 return self.ip == other.ip and self.port == other.port
1107 elif isinstance(other, str):
1108 try:
1109 return (self.ip, self.port) == convert.toIpWithPort(other)
1110 except:
1111 return False
1112 else:
1113 return False
1114
1115 def verify(self):
1116 self.verifyIp()
1117 if self.port < 0 or self.port > 0xffff:
1118 raise TypeError("invalid port %d" % self.port)
1119
1120 def getValue(self):
1121 from _m5.net import IpWithPort
1122 return IpWithPort(self.ip, self.port)
1123
1124time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1125 "%a %b %d %H:%M:%S %Y",
1126 "%Y/%m/%d %H:%M:%S",
1127 "%Y/%m/%d %H:%M",
1128 "%Y/%m/%d",
1129 "%m/%d/%Y %H:%M:%S",
1130 "%m/%d/%Y %H:%M",
1131 "%m/%d/%Y",
1132 "%m/%d/%y %H:%M:%S",
1133 "%m/%d/%y %H:%M",
1134 "%m/%d/%y"]
1135
1136
1137def parse_time(value):
1138 from time import gmtime, strptime, struct_time, time
1139 from datetime import datetime, date
1140
1141 if isinstance(value, struct_time):
1142 return value
1143
1144 if isinstance(value, (int, long)):
1145 return gmtime(value)
1146
1147 if isinstance(value, (datetime, date)):
1148 return value.timetuple()
1149
1150 if isinstance(value, str):
1151 if value in ('Now', 'Today'):
1152 return time.gmtime(time.time())
1153
1154 for format in time_formats:
1155 try:
1156 return strptime(value, format)
1157 except ValueError:
1158 pass
1159
1160 raise ValueError("Could not parse '%s' as a time" % value)
1161
1162class Time(ParamValue):
1163 cxx_type = 'tm'
1164
1165 @classmethod
1166 def cxx_predecls(cls, code):
1167 code('#include <time.h>')
1168
1169 def __init__(self, value):
1170 self.value = parse_time(value)
1171
1172 def __call__(self, value):
1173 self.__init__(value)
1174 return value
1175
1176 def getValue(self):
1177 from _m5.core import tm
1178 import calendar
1179
1180 return tm.gmtime(calendar.timegm(self.value))
1181
1182 def __str__(self):
1183 return time.asctime(self.value)
1184
1185 def ini_str(self):
1186 return str(self)
1187
1188 def get_config_as_dict(self):
1189 assert false
1190 return str(self)
1191
1192 @classmethod
1193 def cxx_ini_predecls(cls, code):
1194 code('#include <time.h>')
1195
1196 @classmethod
1197 def cxx_ini_parse(cls, code, src, dest, ret):
1198 code('char *_parse_ret = strptime((${src}).c_str(),')
1199 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1200 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1201
1202# Enumerated types are a little more complex. The user specifies the
1203# type as Enum(foo) where foo is either a list or dictionary of
1204# alternatives (typically strings, but not necessarily so). (In the
1205# long run, the integer value of the parameter will be the list index
1206# or the corresponding dictionary value. For now, since we only check
1207# that the alternative is valid and then spit it into a .ini file,
1208# there's not much point in using the dictionary.)
1209
1210# What Enum() must do is generate a new type encapsulating the
1211# provided list/dictionary so that specific values of the parameter
1212# can be instances of that type. We define two hidden internal
1213# classes (_ListEnum and _DictEnum) to serve as base classes, then
1214# derive the new type from the appropriate base class on the fly.
1215
1216allEnums = {}
1217# Metaclass for Enum types
1218class MetaEnum(MetaParamValue):
1219 def __new__(mcls, name, bases, dict):
1220 assert name not in allEnums
1221
1222 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1223 allEnums[name] = cls
1224 return cls
1225
1226 def __init__(cls, name, bases, init_dict):
1227 if init_dict.has_key('map'):
1227 if 'map' in init_dict:
1228 if not isinstance(cls.map, dict):
1229 raise TypeError("Enum-derived class attribute 'map' " \
1230 "must be of type dict")
1231 # build list of value strings from map
1232 cls.vals = cls.map.keys()
1233 cls.vals.sort()
1228 if not isinstance(cls.map, dict):
1229 raise TypeError("Enum-derived class attribute 'map' " \
1230 "must be of type dict")
1231 # build list of value strings from map
1232 cls.vals = cls.map.keys()
1233 cls.vals.sort()
1234 elif init_dict.has_key('vals'):
1234 elif 'vals' in init_dict:
1235 if not isinstance(cls.vals, list):
1236 raise TypeError("Enum-derived class attribute 'vals' " \
1237 "must be of type list")
1238 # build string->value map from vals sequence
1239 cls.map = {}
1240 for idx,val in enumerate(cls.vals):
1241 cls.map[val] = idx
1242 else:
1243 raise TypeError("Enum-derived class must define "\
1244 "attribute 'map' or 'vals'")
1245
1246 if cls.is_class:
1247 cls.cxx_type = '%s' % name
1248 else:
1249 cls.cxx_type = 'Enums::%s' % name
1250
1251 super(MetaEnum, cls).__init__(name, bases, init_dict)
1252
1253 # Generate C++ class declaration for this enum type.
1254 # Note that we wrap the enum in a class/struct to act as a namespace,
1255 # so that the enum strings can be brief w/o worrying about collisions.
1256 def cxx_decl(cls, code):
1257 wrapper_name = cls.wrapper_name
1258 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1259 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1260 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1261
1262 code('''\
1263#ifndef $idem_macro
1264#define $idem_macro
1265
1266''')
1267 if cls.is_class:
1268 code('''\
1269enum class $name {
1270''')
1271 else:
1272 code('''\
1273$wrapper $wrapper_name {
1274 enum $name {
1275''')
1276 code.indent(1)
1277 code.indent(1)
1278 for val in cls.vals:
1279 code('$val = ${{cls.map[val]}},')
1280 code('Num_$name = ${{len(cls.vals)}}')
1281 code.dedent(1)
1282 code('};')
1283
1284 if cls.is_class:
1285 code('''\
1286extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1287''')
1288 elif cls.wrapper_is_struct:
1289 code('static const char *${name}Strings[Num_${name}];')
1290 else:
1291 code('extern const char *${name}Strings[Num_${name}];')
1292
1293 if not cls.is_class:
1294 code.dedent(1)
1295 code('};')
1296
1297 code()
1298 code('#endif // $idem_macro')
1299
1300 def cxx_def(cls, code):
1301 wrapper_name = cls.wrapper_name
1302 file_name = cls.__name__
1303 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1304
1305 code('#include "enums/$file_name.hh"')
1306 if cls.wrapper_is_struct:
1307 code('const char *${wrapper_name}::${name}Strings'
1308 '[Num_${name}] =')
1309 else:
1310 if cls.is_class:
1311 code('''\
1312const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1313''')
1314 else:
1315 code('namespace Enums {')
1316 code.indent(1)
1317 code('const char *${name}Strings[Num_${name}] =')
1318
1319 code('{')
1320 code.indent(1)
1321 for val in cls.vals:
1322 code('"$val",')
1323 code.dedent(1)
1324 code('};')
1325
1326 if not cls.wrapper_is_struct and not cls.is_class:
1327 code.dedent(1)
1328 code('} // namespace $wrapper_name')
1329
1330
1331 def pybind_def(cls, code):
1332 name = cls.__name__
1333 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1334 wrapper_name = enum_name if cls.is_class else cls.wrapper_name
1335
1336 code('''#include "pybind11/pybind11.h"
1337#include "pybind11/stl.h"
1338
1339#include <sim/init.hh>
1340
1341namespace py = pybind11;
1342
1343static void
1344module_init(py::module &m_internal)
1345{
1346 py::module m = m_internal.def_submodule("enum_${name}");
1347
1348''')
1349 if cls.is_class:
1350 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1351 else:
1352 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1353
1354 code.indent()
1355 code.indent()
1356 for val in cls.vals:
1357 code('.value("${val}", ${wrapper_name}::${val})')
1358 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1359 code('.export_values()')
1360 code(';')
1361 code.dedent()
1362
1363 code('}')
1364 code.dedent()
1365 code()
1366 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1367
1368
1369# Base class for enum types.
1370class Enum(ParamValue):
1371 __metaclass__ = MetaEnum
1372 vals = []
1373 cmd_line_settable = True
1374
1375 # The name of the wrapping namespace or struct
1376 wrapper_name = 'Enums'
1377
1378 # If true, the enum is wrapped in a struct rather than a namespace
1379 wrapper_is_struct = False
1380
1381 is_class = False
1382
1383 # If not None, use this as the enum name rather than this class name
1384 enum_name = None
1385
1386 def __init__(self, value):
1387 if value not in self.map:
1388 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1389 % (value, self.vals))
1390 self.value = value
1391
1392 def __call__(self, value):
1393 self.__init__(value)
1394 return value
1395
1396 @classmethod
1397 def cxx_predecls(cls, code):
1398 code('#include "enums/$0.hh"', cls.__name__)
1399
1400 @classmethod
1401 def cxx_ini_parse(cls, code, src, dest, ret):
1402 code('if (false) {')
1403 for elem_name in cls.map.iterkeys():
1404 code('} else if (%s == "%s") {' % (src, elem_name))
1405 code.indent()
1406 code('%s = Enums::%s;' % (dest, elem_name))
1407 code('%s true;' % ret)
1408 code.dedent()
1409 code('} else {')
1410 code(' %s false;' % ret)
1411 code('}')
1412
1413 def getValue(self):
1414 import m5.internal.params
1415 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1416 return e(self.map[self.value])
1417
1418 def __str__(self):
1419 return self.value
1420
1421# This param will generate a scoped c++ enum and its python bindings.
1422class ScopedEnum(Enum):
1423 __metaclass__ = MetaEnum
1424 vals = []
1425 cmd_line_settable = True
1426
1427 # The name of the wrapping namespace or struct
1428 wrapper_name = None
1429
1430 # If true, the enum is wrapped in a struct rather than a namespace
1431 wrapper_is_struct = False
1432
1433 # If true, the generated enum is a scoped enum
1434 is_class = True
1435
1436 # If not None, use this as the enum name rather than this class name
1437 enum_name = None
1438
1439# how big does a rounding error need to be before we warn about it?
1440frequency_tolerance = 0.001 # 0.1%
1441
1442class TickParamValue(NumericParamValue):
1443 cxx_type = 'Tick'
1444 ex_str = "1MHz"
1445 cmd_line_settable = True
1446
1447 @classmethod
1448 def cxx_predecls(cls, code):
1449 code('#include "base/types.hh"')
1450
1451 def __call__(self, value):
1452 self.__init__(value)
1453 return value
1454
1455 def getValue(self):
1456 return long(self.value)
1457
1458 @classmethod
1459 def cxx_ini_predecls(cls, code):
1460 code('#include <sstream>')
1461
1462 # Ticks are expressed in seconds in JSON files and in plain
1463 # Ticks in .ini files. Switch based on a config flag
1464 @classmethod
1465 def cxx_ini_parse(self, code, src, dest, ret):
1466 code('${ret} to_number(${src}, ${dest});')
1467
1468class Latency(TickParamValue):
1469 ex_str = "100ns"
1470
1471 def __init__(self, value):
1472 if isinstance(value, (Latency, Clock)):
1473 self.ticks = value.ticks
1474 self.value = value.value
1475 elif isinstance(value, Frequency):
1476 self.ticks = value.ticks
1477 self.value = 1.0 / value.value
1478 elif value.endswith('t'):
1479 self.ticks = True
1480 self.value = int(value[:-1])
1481 else:
1482 self.ticks = False
1483 self.value = convert.toLatency(value)
1484
1485 def __call__(self, value):
1486 self.__init__(value)
1487 return value
1488
1489 def __getattr__(self, attr):
1490 if attr in ('latency', 'period'):
1491 return self
1492 if attr == 'frequency':
1493 return Frequency(self)
1494 raise AttributeError("Latency object has no attribute '%s'" % attr)
1495
1496 def getValue(self):
1497 if self.ticks or self.value == 0:
1498 value = self.value
1499 else:
1500 value = ticks.fromSeconds(self.value)
1501 return long(value)
1502
1503 def config_value(self):
1504 return self.getValue()
1505
1506 # convert latency to ticks
1507 def ini_str(self):
1508 return '%d' % self.getValue()
1509
1510class Frequency(TickParamValue):
1511 ex_str = "1GHz"
1512
1513 def __init__(self, value):
1514 if isinstance(value, (Latency, Clock)):
1515 if value.value == 0:
1516 self.value = 0
1517 else:
1518 self.value = 1.0 / value.value
1519 self.ticks = value.ticks
1520 elif isinstance(value, Frequency):
1521 self.value = value.value
1522 self.ticks = value.ticks
1523 else:
1524 self.ticks = False
1525 self.value = convert.toFrequency(value)
1526
1527 def __call__(self, value):
1528 self.__init__(value)
1529 return value
1530
1531 def __getattr__(self, attr):
1532 if attr == 'frequency':
1533 return self
1534 if attr in ('latency', 'period'):
1535 return Latency(self)
1536 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1537
1538 # convert latency to ticks
1539 def getValue(self):
1540 if self.ticks or self.value == 0:
1541 value = self.value
1542 else:
1543 value = ticks.fromSeconds(1.0 / self.value)
1544 return long(value)
1545
1546 def config_value(self):
1547 return self.getValue()
1548
1549 def ini_str(self):
1550 return '%d' % self.getValue()
1551
1552# A generic Frequency and/or Latency value. Value is stored as a
1553# latency, just like Latency and Frequency.
1554class Clock(TickParamValue):
1555 def __init__(self, value):
1556 if isinstance(value, (Latency, Clock)):
1557 self.ticks = value.ticks
1558 self.value = value.value
1559 elif isinstance(value, Frequency):
1560 self.ticks = value.ticks
1561 self.value = 1.0 / value.value
1562 elif value.endswith('t'):
1563 self.ticks = True
1564 self.value = int(value[:-1])
1565 else:
1566 self.ticks = False
1567 self.value = convert.anyToLatency(value)
1568
1569 def __call__(self, value):
1570 self.__init__(value)
1571 return value
1572
1573 def __str__(self):
1574 return "%s" % Latency(self)
1575
1576 def __getattr__(self, attr):
1577 if attr == 'frequency':
1578 return Frequency(self)
1579 if attr in ('latency', 'period'):
1580 return Latency(self)
1581 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1582
1583 def getValue(self):
1584 return self.period.getValue()
1585
1586 def config_value(self):
1587 return self.period.config_value()
1588
1589 def ini_str(self):
1590 return self.period.ini_str()
1591
1592class Voltage(Float):
1593 ex_str = "1V"
1594
1595 def __new__(cls, value):
1596 value = convert.toVoltage(value)
1597 return super(cls, Voltage).__new__(cls, value)
1598
1599 def __init__(self, value):
1600 value = convert.toVoltage(value)
1601 super(Voltage, self).__init__(value)
1602
1603class Current(Float):
1604 ex_str = "1mA"
1605
1606 def __new__(cls, value):
1607 value = convert.toCurrent(value)
1608 return super(cls, Current).__new__(cls, value)
1609
1610 def __init__(self, value):
1611 value = convert.toCurrent(value)
1612 super(Current, self).__init__(value)
1613
1614class Energy(Float):
1615 ex_str = "1pJ"
1616
1617 def __new__(cls, value):
1618 value = convert.toEnergy(value)
1619 return super(cls, Energy).__new__(cls, value)
1620
1621 def __init__(self, value):
1622 value = convert.toEnergy(value)
1623 super(Energy, self).__init__(value)
1624
1625class NetworkBandwidth(float,ParamValue):
1626 cxx_type = 'float'
1627 ex_str = "1Gbps"
1628 cmd_line_settable = True
1629
1630 def __new__(cls, value):
1631 # convert to bits per second
1632 val = convert.toNetworkBandwidth(value)
1633 return super(cls, NetworkBandwidth).__new__(cls, val)
1634
1635 def __str__(self):
1636 return str(self.val)
1637
1638 def __call__(self, value):
1639 val = convert.toNetworkBandwidth(value)
1640 self.__init__(val)
1641 return value
1642
1643 def getValue(self):
1644 # convert to seconds per byte
1645 value = 8.0 / float(self)
1646 # convert to ticks per byte
1647 value = ticks.fromSeconds(value)
1648 return float(value)
1649
1650 def ini_str(self):
1651 return '%f' % self.getValue()
1652
1653 def config_value(self):
1654 return '%f' % self.getValue()
1655
1656 @classmethod
1657 def cxx_ini_predecls(cls, code):
1658 code('#include <sstream>')
1659
1660 @classmethod
1661 def cxx_ini_parse(self, code, src, dest, ret):
1662 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1663
1664class MemoryBandwidth(float,ParamValue):
1665 cxx_type = 'float'
1666 ex_str = "1GB/s"
1667 cmd_line_settable = True
1668
1669 def __new__(cls, value):
1670 # convert to bytes per second
1671 val = convert.toMemoryBandwidth(value)
1672 return super(cls, MemoryBandwidth).__new__(cls, val)
1673
1674 def __call__(self, value):
1675 val = convert.toMemoryBandwidth(value)
1676 self.__init__(val)
1677 return value
1678
1679 def getValue(self):
1680 # convert to seconds per byte
1681 value = float(self)
1682 if value:
1683 value = 1.0 / float(self)
1684 # convert to ticks per byte
1685 value = ticks.fromSeconds(value)
1686 return float(value)
1687
1688 def ini_str(self):
1689 return '%f' % self.getValue()
1690
1691 def config_value(self):
1692 return '%f' % self.getValue()
1693
1694 @classmethod
1695 def cxx_ini_predecls(cls, code):
1696 code('#include <sstream>')
1697
1698 @classmethod
1699 def cxx_ini_parse(self, code, src, dest, ret):
1700 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1701
1702#
1703# "Constants"... handy aliases for various values.
1704#
1705
1706# Special class for NULL pointers. Note the special check in
1707# make_param_value() above that lets these be assigned where a
1708# SimObject is required.
1709# only one copy of a particular node
1710class NullSimObject(object):
1711 __metaclass__ = Singleton
1712 _name = 'Null'
1713
1714 def __call__(cls):
1715 return cls
1716
1717 def _instantiate(self, parent = None, path = ''):
1718 pass
1719
1720 def ini_str(self):
1721 return 'Null'
1722
1723 def unproxy(self, base):
1724 return self
1725
1726 def set_path(self, parent, name):
1727 pass
1728
1729 def set_parent(self, parent, name):
1730 pass
1731
1732 def clear_parent(self, old_parent):
1733 pass
1734
1735 def descendants(self):
1736 return
1737 yield None
1738
1739 def get_config_as_dict(self):
1740 return {}
1741
1742 def __str__(self):
1743 return self._name
1744
1745 def config_value(self):
1746 return None
1747
1748 def getValue(self):
1749 return None
1750
1751# The only instance you'll ever need...
1752NULL = NullSimObject()
1753
1754def isNullPointer(value):
1755 return isinstance(value, NullSimObject)
1756
1757# Some memory range specifications use this as a default upper bound.
1758MaxAddr = Addr.max
1759MaxTick = Tick.max
1760AllMemory = AddrRange(0, MaxAddr)
1761
1762
1763#####################################################################
1764#
1765# Port objects
1766#
1767# Ports are used to interconnect objects in the memory system.
1768#
1769#####################################################################
1770
1771# Port reference: encapsulates a reference to a particular port on a
1772# particular SimObject.
1773class PortRef(object):
1774 def __init__(self, simobj, name, role):
1775 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1776 self.simobj = simobj
1777 self.name = name
1778 self.role = role
1779 self.peer = None # not associated with another port yet
1780 self.ccConnected = False # C++ port connection done?
1781 self.index = -1 # always -1 for non-vector ports
1782
1783 def __str__(self):
1784 return '%s.%s' % (self.simobj, self.name)
1785
1786 def __len__(self):
1787 # Return the number of connected ports, i.e. 0 is we have no
1788 # peer and 1 if we do.
1789 return int(self.peer != None)
1790
1791 # for config.ini, print peer's name (not ours)
1792 def ini_str(self):
1793 return str(self.peer)
1794
1795 # for config.json
1796 def get_config_as_dict(self):
1797 return {'role' : self.role, 'peer' : str(self.peer)}
1798
1799 def __getattr__(self, attr):
1800 if attr == 'peerObj':
1801 # shorthand for proxies
1802 return self.peer.simobj
1803 raise AttributeError("'%s' object has no attribute '%s'" % \
1804 (self.__class__.__name__, attr))
1805
1806 # Full connection is symmetric (both ways). Called via
1807 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1808 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1809 # e.g., "obj1.portA[3] = obj2.portB".
1810 def connect(self, other):
1811 if isinstance(other, VectorPortRef):
1812 # reference to plain VectorPort is implicit append
1813 other = other._get_next()
1814 if self.peer and not proxy.isproxy(self.peer):
1815 fatal("Port %s is already connected to %s, cannot connect %s\n",
1816 self, self.peer, other);
1817 self.peer = other
1818 if proxy.isproxy(other):
1819 other.set_param_desc(PortParamDesc())
1820 elif isinstance(other, PortRef):
1821 if other.peer is not self:
1822 other.connect(self)
1823 else:
1824 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1825 % (other, self))
1826
1827 # Allow a master/slave port pair to be spliced between
1828 # a port and its connected peer. Useful operation for connecting
1829 # instrumentation structures into a system when it is necessary
1830 # to connect the instrumentation after the full system has been
1831 # constructed.
1832 def splice(self, new_master_peer, new_slave_peer):
1833 if not self.peer or proxy.isproxy(self.peer):
1834 fatal("Port %s not connected, cannot splice in new peers\n", self)
1835
1836 if not isinstance(new_master_peer, PortRef) or \
1837 not isinstance(new_slave_peer, PortRef):
1838 raise TypeError(
1839 "Splicing non-port references '%s','%s' to port '%s'" % \
1840 (new_master_peer, new_slave_peer, self))
1841
1842 old_peer = self.peer
1843 if self.role == 'SLAVE':
1844 self.peer = new_master_peer
1845 old_peer.peer = new_slave_peer
1846 new_master_peer.connect(self)
1847 new_slave_peer.connect(old_peer)
1848 elif self.role == 'MASTER':
1849 self.peer = new_slave_peer
1850 old_peer.peer = new_master_peer
1851 new_slave_peer.connect(self)
1852 new_master_peer.connect(old_peer)
1853 else:
1854 panic("Port %s has unknown role, "+\
1855 "cannot splice in new peers\n", self)
1856
1857 def clone(self, simobj, memo):
1235 if not isinstance(cls.vals, list):
1236 raise TypeError("Enum-derived class attribute 'vals' " \
1237 "must be of type list")
1238 # build string->value map from vals sequence
1239 cls.map = {}
1240 for idx,val in enumerate(cls.vals):
1241 cls.map[val] = idx
1242 else:
1243 raise TypeError("Enum-derived class must define "\
1244 "attribute 'map' or 'vals'")
1245
1246 if cls.is_class:
1247 cls.cxx_type = '%s' % name
1248 else:
1249 cls.cxx_type = 'Enums::%s' % name
1250
1251 super(MetaEnum, cls).__init__(name, bases, init_dict)
1252
1253 # Generate C++ class declaration for this enum type.
1254 # Note that we wrap the enum in a class/struct to act as a namespace,
1255 # so that the enum strings can be brief w/o worrying about collisions.
1256 def cxx_decl(cls, code):
1257 wrapper_name = cls.wrapper_name
1258 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1259 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1260 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1261
1262 code('''\
1263#ifndef $idem_macro
1264#define $idem_macro
1265
1266''')
1267 if cls.is_class:
1268 code('''\
1269enum class $name {
1270''')
1271 else:
1272 code('''\
1273$wrapper $wrapper_name {
1274 enum $name {
1275''')
1276 code.indent(1)
1277 code.indent(1)
1278 for val in cls.vals:
1279 code('$val = ${{cls.map[val]}},')
1280 code('Num_$name = ${{len(cls.vals)}}')
1281 code.dedent(1)
1282 code('};')
1283
1284 if cls.is_class:
1285 code('''\
1286extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1287''')
1288 elif cls.wrapper_is_struct:
1289 code('static const char *${name}Strings[Num_${name}];')
1290 else:
1291 code('extern const char *${name}Strings[Num_${name}];')
1292
1293 if not cls.is_class:
1294 code.dedent(1)
1295 code('};')
1296
1297 code()
1298 code('#endif // $idem_macro')
1299
1300 def cxx_def(cls, code):
1301 wrapper_name = cls.wrapper_name
1302 file_name = cls.__name__
1303 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1304
1305 code('#include "enums/$file_name.hh"')
1306 if cls.wrapper_is_struct:
1307 code('const char *${wrapper_name}::${name}Strings'
1308 '[Num_${name}] =')
1309 else:
1310 if cls.is_class:
1311 code('''\
1312const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1313''')
1314 else:
1315 code('namespace Enums {')
1316 code.indent(1)
1317 code('const char *${name}Strings[Num_${name}] =')
1318
1319 code('{')
1320 code.indent(1)
1321 for val in cls.vals:
1322 code('"$val",')
1323 code.dedent(1)
1324 code('};')
1325
1326 if not cls.wrapper_is_struct and not cls.is_class:
1327 code.dedent(1)
1328 code('} // namespace $wrapper_name')
1329
1330
1331 def pybind_def(cls, code):
1332 name = cls.__name__
1333 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1334 wrapper_name = enum_name if cls.is_class else cls.wrapper_name
1335
1336 code('''#include "pybind11/pybind11.h"
1337#include "pybind11/stl.h"
1338
1339#include <sim/init.hh>
1340
1341namespace py = pybind11;
1342
1343static void
1344module_init(py::module &m_internal)
1345{
1346 py::module m = m_internal.def_submodule("enum_${name}");
1347
1348''')
1349 if cls.is_class:
1350 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1351 else:
1352 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1353
1354 code.indent()
1355 code.indent()
1356 for val in cls.vals:
1357 code('.value("${val}", ${wrapper_name}::${val})')
1358 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1359 code('.export_values()')
1360 code(';')
1361 code.dedent()
1362
1363 code('}')
1364 code.dedent()
1365 code()
1366 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1367
1368
1369# Base class for enum types.
1370class Enum(ParamValue):
1371 __metaclass__ = MetaEnum
1372 vals = []
1373 cmd_line_settable = True
1374
1375 # The name of the wrapping namespace or struct
1376 wrapper_name = 'Enums'
1377
1378 # If true, the enum is wrapped in a struct rather than a namespace
1379 wrapper_is_struct = False
1380
1381 is_class = False
1382
1383 # If not None, use this as the enum name rather than this class name
1384 enum_name = None
1385
1386 def __init__(self, value):
1387 if value not in self.map:
1388 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1389 % (value, self.vals))
1390 self.value = value
1391
1392 def __call__(self, value):
1393 self.__init__(value)
1394 return value
1395
1396 @classmethod
1397 def cxx_predecls(cls, code):
1398 code('#include "enums/$0.hh"', cls.__name__)
1399
1400 @classmethod
1401 def cxx_ini_parse(cls, code, src, dest, ret):
1402 code('if (false) {')
1403 for elem_name in cls.map.iterkeys():
1404 code('} else if (%s == "%s") {' % (src, elem_name))
1405 code.indent()
1406 code('%s = Enums::%s;' % (dest, elem_name))
1407 code('%s true;' % ret)
1408 code.dedent()
1409 code('} else {')
1410 code(' %s false;' % ret)
1411 code('}')
1412
1413 def getValue(self):
1414 import m5.internal.params
1415 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1416 return e(self.map[self.value])
1417
1418 def __str__(self):
1419 return self.value
1420
1421# This param will generate a scoped c++ enum and its python bindings.
1422class ScopedEnum(Enum):
1423 __metaclass__ = MetaEnum
1424 vals = []
1425 cmd_line_settable = True
1426
1427 # The name of the wrapping namespace or struct
1428 wrapper_name = None
1429
1430 # If true, the enum is wrapped in a struct rather than a namespace
1431 wrapper_is_struct = False
1432
1433 # If true, the generated enum is a scoped enum
1434 is_class = True
1435
1436 # If not None, use this as the enum name rather than this class name
1437 enum_name = None
1438
1439# how big does a rounding error need to be before we warn about it?
1440frequency_tolerance = 0.001 # 0.1%
1441
1442class TickParamValue(NumericParamValue):
1443 cxx_type = 'Tick'
1444 ex_str = "1MHz"
1445 cmd_line_settable = True
1446
1447 @classmethod
1448 def cxx_predecls(cls, code):
1449 code('#include "base/types.hh"')
1450
1451 def __call__(self, value):
1452 self.__init__(value)
1453 return value
1454
1455 def getValue(self):
1456 return long(self.value)
1457
1458 @classmethod
1459 def cxx_ini_predecls(cls, code):
1460 code('#include <sstream>')
1461
1462 # Ticks are expressed in seconds in JSON files and in plain
1463 # Ticks in .ini files. Switch based on a config flag
1464 @classmethod
1465 def cxx_ini_parse(self, code, src, dest, ret):
1466 code('${ret} to_number(${src}, ${dest});')
1467
1468class Latency(TickParamValue):
1469 ex_str = "100ns"
1470
1471 def __init__(self, value):
1472 if isinstance(value, (Latency, Clock)):
1473 self.ticks = value.ticks
1474 self.value = value.value
1475 elif isinstance(value, Frequency):
1476 self.ticks = value.ticks
1477 self.value = 1.0 / value.value
1478 elif value.endswith('t'):
1479 self.ticks = True
1480 self.value = int(value[:-1])
1481 else:
1482 self.ticks = False
1483 self.value = convert.toLatency(value)
1484
1485 def __call__(self, value):
1486 self.__init__(value)
1487 return value
1488
1489 def __getattr__(self, attr):
1490 if attr in ('latency', 'period'):
1491 return self
1492 if attr == 'frequency':
1493 return Frequency(self)
1494 raise AttributeError("Latency object has no attribute '%s'" % attr)
1495
1496 def getValue(self):
1497 if self.ticks or self.value == 0:
1498 value = self.value
1499 else:
1500 value = ticks.fromSeconds(self.value)
1501 return long(value)
1502
1503 def config_value(self):
1504 return self.getValue()
1505
1506 # convert latency to ticks
1507 def ini_str(self):
1508 return '%d' % self.getValue()
1509
1510class Frequency(TickParamValue):
1511 ex_str = "1GHz"
1512
1513 def __init__(self, value):
1514 if isinstance(value, (Latency, Clock)):
1515 if value.value == 0:
1516 self.value = 0
1517 else:
1518 self.value = 1.0 / value.value
1519 self.ticks = value.ticks
1520 elif isinstance(value, Frequency):
1521 self.value = value.value
1522 self.ticks = value.ticks
1523 else:
1524 self.ticks = False
1525 self.value = convert.toFrequency(value)
1526
1527 def __call__(self, value):
1528 self.__init__(value)
1529 return value
1530
1531 def __getattr__(self, attr):
1532 if attr == 'frequency':
1533 return self
1534 if attr in ('latency', 'period'):
1535 return Latency(self)
1536 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1537
1538 # convert latency to ticks
1539 def getValue(self):
1540 if self.ticks or self.value == 0:
1541 value = self.value
1542 else:
1543 value = ticks.fromSeconds(1.0 / self.value)
1544 return long(value)
1545
1546 def config_value(self):
1547 return self.getValue()
1548
1549 def ini_str(self):
1550 return '%d' % self.getValue()
1551
1552# A generic Frequency and/or Latency value. Value is stored as a
1553# latency, just like Latency and Frequency.
1554class Clock(TickParamValue):
1555 def __init__(self, value):
1556 if isinstance(value, (Latency, Clock)):
1557 self.ticks = value.ticks
1558 self.value = value.value
1559 elif isinstance(value, Frequency):
1560 self.ticks = value.ticks
1561 self.value = 1.0 / value.value
1562 elif value.endswith('t'):
1563 self.ticks = True
1564 self.value = int(value[:-1])
1565 else:
1566 self.ticks = False
1567 self.value = convert.anyToLatency(value)
1568
1569 def __call__(self, value):
1570 self.__init__(value)
1571 return value
1572
1573 def __str__(self):
1574 return "%s" % Latency(self)
1575
1576 def __getattr__(self, attr):
1577 if attr == 'frequency':
1578 return Frequency(self)
1579 if attr in ('latency', 'period'):
1580 return Latency(self)
1581 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1582
1583 def getValue(self):
1584 return self.period.getValue()
1585
1586 def config_value(self):
1587 return self.period.config_value()
1588
1589 def ini_str(self):
1590 return self.period.ini_str()
1591
1592class Voltage(Float):
1593 ex_str = "1V"
1594
1595 def __new__(cls, value):
1596 value = convert.toVoltage(value)
1597 return super(cls, Voltage).__new__(cls, value)
1598
1599 def __init__(self, value):
1600 value = convert.toVoltage(value)
1601 super(Voltage, self).__init__(value)
1602
1603class Current(Float):
1604 ex_str = "1mA"
1605
1606 def __new__(cls, value):
1607 value = convert.toCurrent(value)
1608 return super(cls, Current).__new__(cls, value)
1609
1610 def __init__(self, value):
1611 value = convert.toCurrent(value)
1612 super(Current, self).__init__(value)
1613
1614class Energy(Float):
1615 ex_str = "1pJ"
1616
1617 def __new__(cls, value):
1618 value = convert.toEnergy(value)
1619 return super(cls, Energy).__new__(cls, value)
1620
1621 def __init__(self, value):
1622 value = convert.toEnergy(value)
1623 super(Energy, self).__init__(value)
1624
1625class NetworkBandwidth(float,ParamValue):
1626 cxx_type = 'float'
1627 ex_str = "1Gbps"
1628 cmd_line_settable = True
1629
1630 def __new__(cls, value):
1631 # convert to bits per second
1632 val = convert.toNetworkBandwidth(value)
1633 return super(cls, NetworkBandwidth).__new__(cls, val)
1634
1635 def __str__(self):
1636 return str(self.val)
1637
1638 def __call__(self, value):
1639 val = convert.toNetworkBandwidth(value)
1640 self.__init__(val)
1641 return value
1642
1643 def getValue(self):
1644 # convert to seconds per byte
1645 value = 8.0 / float(self)
1646 # convert to ticks per byte
1647 value = ticks.fromSeconds(value)
1648 return float(value)
1649
1650 def ini_str(self):
1651 return '%f' % self.getValue()
1652
1653 def config_value(self):
1654 return '%f' % self.getValue()
1655
1656 @classmethod
1657 def cxx_ini_predecls(cls, code):
1658 code('#include <sstream>')
1659
1660 @classmethod
1661 def cxx_ini_parse(self, code, src, dest, ret):
1662 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1663
1664class MemoryBandwidth(float,ParamValue):
1665 cxx_type = 'float'
1666 ex_str = "1GB/s"
1667 cmd_line_settable = True
1668
1669 def __new__(cls, value):
1670 # convert to bytes per second
1671 val = convert.toMemoryBandwidth(value)
1672 return super(cls, MemoryBandwidth).__new__(cls, val)
1673
1674 def __call__(self, value):
1675 val = convert.toMemoryBandwidth(value)
1676 self.__init__(val)
1677 return value
1678
1679 def getValue(self):
1680 # convert to seconds per byte
1681 value = float(self)
1682 if value:
1683 value = 1.0 / float(self)
1684 # convert to ticks per byte
1685 value = ticks.fromSeconds(value)
1686 return float(value)
1687
1688 def ini_str(self):
1689 return '%f' % self.getValue()
1690
1691 def config_value(self):
1692 return '%f' % self.getValue()
1693
1694 @classmethod
1695 def cxx_ini_predecls(cls, code):
1696 code('#include <sstream>')
1697
1698 @classmethod
1699 def cxx_ini_parse(self, code, src, dest, ret):
1700 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1701
1702#
1703# "Constants"... handy aliases for various values.
1704#
1705
1706# Special class for NULL pointers. Note the special check in
1707# make_param_value() above that lets these be assigned where a
1708# SimObject is required.
1709# only one copy of a particular node
1710class NullSimObject(object):
1711 __metaclass__ = Singleton
1712 _name = 'Null'
1713
1714 def __call__(cls):
1715 return cls
1716
1717 def _instantiate(self, parent = None, path = ''):
1718 pass
1719
1720 def ini_str(self):
1721 return 'Null'
1722
1723 def unproxy(self, base):
1724 return self
1725
1726 def set_path(self, parent, name):
1727 pass
1728
1729 def set_parent(self, parent, name):
1730 pass
1731
1732 def clear_parent(self, old_parent):
1733 pass
1734
1735 def descendants(self):
1736 return
1737 yield None
1738
1739 def get_config_as_dict(self):
1740 return {}
1741
1742 def __str__(self):
1743 return self._name
1744
1745 def config_value(self):
1746 return None
1747
1748 def getValue(self):
1749 return None
1750
1751# The only instance you'll ever need...
1752NULL = NullSimObject()
1753
1754def isNullPointer(value):
1755 return isinstance(value, NullSimObject)
1756
1757# Some memory range specifications use this as a default upper bound.
1758MaxAddr = Addr.max
1759MaxTick = Tick.max
1760AllMemory = AddrRange(0, MaxAddr)
1761
1762
1763#####################################################################
1764#
1765# Port objects
1766#
1767# Ports are used to interconnect objects in the memory system.
1768#
1769#####################################################################
1770
1771# Port reference: encapsulates a reference to a particular port on a
1772# particular SimObject.
1773class PortRef(object):
1774 def __init__(self, simobj, name, role):
1775 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1776 self.simobj = simobj
1777 self.name = name
1778 self.role = role
1779 self.peer = None # not associated with another port yet
1780 self.ccConnected = False # C++ port connection done?
1781 self.index = -1 # always -1 for non-vector ports
1782
1783 def __str__(self):
1784 return '%s.%s' % (self.simobj, self.name)
1785
1786 def __len__(self):
1787 # Return the number of connected ports, i.e. 0 is we have no
1788 # peer and 1 if we do.
1789 return int(self.peer != None)
1790
1791 # for config.ini, print peer's name (not ours)
1792 def ini_str(self):
1793 return str(self.peer)
1794
1795 # for config.json
1796 def get_config_as_dict(self):
1797 return {'role' : self.role, 'peer' : str(self.peer)}
1798
1799 def __getattr__(self, attr):
1800 if attr == 'peerObj':
1801 # shorthand for proxies
1802 return self.peer.simobj
1803 raise AttributeError("'%s' object has no attribute '%s'" % \
1804 (self.__class__.__name__, attr))
1805
1806 # Full connection is symmetric (both ways). Called via
1807 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1808 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1809 # e.g., "obj1.portA[3] = obj2.portB".
1810 def connect(self, other):
1811 if isinstance(other, VectorPortRef):
1812 # reference to plain VectorPort is implicit append
1813 other = other._get_next()
1814 if self.peer and not proxy.isproxy(self.peer):
1815 fatal("Port %s is already connected to %s, cannot connect %s\n",
1816 self, self.peer, other);
1817 self.peer = other
1818 if proxy.isproxy(other):
1819 other.set_param_desc(PortParamDesc())
1820 elif isinstance(other, PortRef):
1821 if other.peer is not self:
1822 other.connect(self)
1823 else:
1824 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1825 % (other, self))
1826
1827 # Allow a master/slave port pair to be spliced between
1828 # a port and its connected peer. Useful operation for connecting
1829 # instrumentation structures into a system when it is necessary
1830 # to connect the instrumentation after the full system has been
1831 # constructed.
1832 def splice(self, new_master_peer, new_slave_peer):
1833 if not self.peer or proxy.isproxy(self.peer):
1834 fatal("Port %s not connected, cannot splice in new peers\n", self)
1835
1836 if not isinstance(new_master_peer, PortRef) or \
1837 not isinstance(new_slave_peer, PortRef):
1838 raise TypeError(
1839 "Splicing non-port references '%s','%s' to port '%s'" % \
1840 (new_master_peer, new_slave_peer, self))
1841
1842 old_peer = self.peer
1843 if self.role == 'SLAVE':
1844 self.peer = new_master_peer
1845 old_peer.peer = new_slave_peer
1846 new_master_peer.connect(self)
1847 new_slave_peer.connect(old_peer)
1848 elif self.role == 'MASTER':
1849 self.peer = new_slave_peer
1850 old_peer.peer = new_master_peer
1851 new_slave_peer.connect(self)
1852 new_master_peer.connect(old_peer)
1853 else:
1854 panic("Port %s has unknown role, "+\
1855 "cannot splice in new peers\n", self)
1856
1857 def clone(self, simobj, memo):
1858 if memo.has_key(self):
1858 if self in memo:
1859 return memo[self]
1860 newRef = copy.copy(self)
1861 memo[self] = newRef
1862 newRef.simobj = simobj
1863 assert(isSimObject(newRef.simobj))
1864 if self.peer and not proxy.isproxy(self.peer):
1865 peerObj = self.peer.simobj(_memo=memo)
1866 newRef.peer = self.peer.clone(peerObj, memo)
1867 assert(not isinstance(newRef.peer, VectorPortRef))
1868 return newRef
1869
1870 def unproxy(self, simobj):
1871 assert(simobj is self.simobj)
1872 if proxy.isproxy(self.peer):
1873 try:
1874 realPeer = self.peer.unproxy(self.simobj)
1875 except:
1876 print("Error in unproxying port '%s' of %s" %
1877 (self.name, self.simobj.path()))
1878 raise
1879 self.connect(realPeer)
1880
1881 # Call C++ to create corresponding port connection between C++ objects
1882 def ccConnect(self):
1883 from _m5.pyobject import connectPorts
1884
1885 if self.ccConnected: # already done this
1886 return
1887
1888 peer = self.peer
1889 if not self.peer: # nothing to connect to
1890 return
1891
1892 # check that we connect a master to a slave
1893 if self.role == peer.role:
1894 raise TypeError(
1895 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1896 (peer, self, self.role))
1897
1898 if self.role == 'SLAVE':
1899 # do nothing and let the master take care of it
1900 return
1901
1902 try:
1903 # self is always the master and peer the slave
1904 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1905 peer.simobj.getCCObject(), peer.name, peer.index)
1906 except:
1907 print("Error connecting port %s.%s to %s.%s" %
1908 (self.simobj.path(), self.name,
1909 peer.simobj.path(), peer.name))
1910 raise
1911 self.ccConnected = True
1912 peer.ccConnected = True
1913
1914# A reference to an individual element of a VectorPort... much like a
1915# PortRef, but has an index.
1916class VectorPortElementRef(PortRef):
1917 def __init__(self, simobj, name, role, index):
1918 PortRef.__init__(self, simobj, name, role)
1919 self.index = index
1920
1921 def __str__(self):
1922 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1923
1924# A reference to a complete vector-valued port (not just a single element).
1925# Can be indexed to retrieve individual VectorPortElementRef instances.
1926class VectorPortRef(object):
1927 def __init__(self, simobj, name, role):
1928 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1929 self.simobj = simobj
1930 self.name = name
1931 self.role = role
1932 self.elements = []
1933
1934 def __str__(self):
1935 return '%s.%s[:]' % (self.simobj, self.name)
1936
1937 def __len__(self):
1938 # Return the number of connected peers, corresponding the the
1939 # length of the elements.
1940 return len(self.elements)
1941
1942 # for config.ini, print peer's name (not ours)
1943 def ini_str(self):
1944 return ' '.join([el.ini_str() for el in self.elements])
1945
1946 # for config.json
1947 def get_config_as_dict(self):
1948 return {'role' : self.role,
1949 'peer' : [el.ini_str() for el in self.elements]}
1950
1951 def __getitem__(self, key):
1952 if not isinstance(key, int):
1953 raise TypeError("VectorPort index must be integer")
1954 if key >= len(self.elements):
1955 # need to extend list
1956 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1957 for i in range(len(self.elements), key+1)]
1958 self.elements.extend(ext)
1959 return self.elements[key]
1960
1961 def _get_next(self):
1962 return self[len(self.elements)]
1963
1964 def __setitem__(self, key, value):
1965 if not isinstance(key, int):
1966 raise TypeError("VectorPort index must be integer")
1967 self[key].connect(value)
1968
1969 def connect(self, other):
1970 if isinstance(other, (list, tuple)):
1971 # Assign list of port refs to vector port.
1972 # For now, append them... not sure if that's the right semantics
1973 # or if it should replace the current vector.
1974 for ref in other:
1975 self._get_next().connect(ref)
1976 else:
1977 # scalar assignment to plain VectorPort is implicit append
1978 self._get_next().connect(other)
1979
1980 def clone(self, simobj, memo):
1859 return memo[self]
1860 newRef = copy.copy(self)
1861 memo[self] = newRef
1862 newRef.simobj = simobj
1863 assert(isSimObject(newRef.simobj))
1864 if self.peer and not proxy.isproxy(self.peer):
1865 peerObj = self.peer.simobj(_memo=memo)
1866 newRef.peer = self.peer.clone(peerObj, memo)
1867 assert(not isinstance(newRef.peer, VectorPortRef))
1868 return newRef
1869
1870 def unproxy(self, simobj):
1871 assert(simobj is self.simobj)
1872 if proxy.isproxy(self.peer):
1873 try:
1874 realPeer = self.peer.unproxy(self.simobj)
1875 except:
1876 print("Error in unproxying port '%s' of %s" %
1877 (self.name, self.simobj.path()))
1878 raise
1879 self.connect(realPeer)
1880
1881 # Call C++ to create corresponding port connection between C++ objects
1882 def ccConnect(self):
1883 from _m5.pyobject import connectPorts
1884
1885 if self.ccConnected: # already done this
1886 return
1887
1888 peer = self.peer
1889 if not self.peer: # nothing to connect to
1890 return
1891
1892 # check that we connect a master to a slave
1893 if self.role == peer.role:
1894 raise TypeError(
1895 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1896 (peer, self, self.role))
1897
1898 if self.role == 'SLAVE':
1899 # do nothing and let the master take care of it
1900 return
1901
1902 try:
1903 # self is always the master and peer the slave
1904 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1905 peer.simobj.getCCObject(), peer.name, peer.index)
1906 except:
1907 print("Error connecting port %s.%s to %s.%s" %
1908 (self.simobj.path(), self.name,
1909 peer.simobj.path(), peer.name))
1910 raise
1911 self.ccConnected = True
1912 peer.ccConnected = True
1913
1914# A reference to an individual element of a VectorPort... much like a
1915# PortRef, but has an index.
1916class VectorPortElementRef(PortRef):
1917 def __init__(self, simobj, name, role, index):
1918 PortRef.__init__(self, simobj, name, role)
1919 self.index = index
1920
1921 def __str__(self):
1922 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1923
1924# A reference to a complete vector-valued port (not just a single element).
1925# Can be indexed to retrieve individual VectorPortElementRef instances.
1926class VectorPortRef(object):
1927 def __init__(self, simobj, name, role):
1928 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1929 self.simobj = simobj
1930 self.name = name
1931 self.role = role
1932 self.elements = []
1933
1934 def __str__(self):
1935 return '%s.%s[:]' % (self.simobj, self.name)
1936
1937 def __len__(self):
1938 # Return the number of connected peers, corresponding the the
1939 # length of the elements.
1940 return len(self.elements)
1941
1942 # for config.ini, print peer's name (not ours)
1943 def ini_str(self):
1944 return ' '.join([el.ini_str() for el in self.elements])
1945
1946 # for config.json
1947 def get_config_as_dict(self):
1948 return {'role' : self.role,
1949 'peer' : [el.ini_str() for el in self.elements]}
1950
1951 def __getitem__(self, key):
1952 if not isinstance(key, int):
1953 raise TypeError("VectorPort index must be integer")
1954 if key >= len(self.elements):
1955 # need to extend list
1956 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1957 for i in range(len(self.elements), key+1)]
1958 self.elements.extend(ext)
1959 return self.elements[key]
1960
1961 def _get_next(self):
1962 return self[len(self.elements)]
1963
1964 def __setitem__(self, key, value):
1965 if not isinstance(key, int):
1966 raise TypeError("VectorPort index must be integer")
1967 self[key].connect(value)
1968
1969 def connect(self, other):
1970 if isinstance(other, (list, tuple)):
1971 # Assign list of port refs to vector port.
1972 # For now, append them... not sure if that's the right semantics
1973 # or if it should replace the current vector.
1974 for ref in other:
1975 self._get_next().connect(ref)
1976 else:
1977 # scalar assignment to plain VectorPort is implicit append
1978 self._get_next().connect(other)
1979
1980 def clone(self, simobj, memo):
1981 if memo.has_key(self):
1981 if self in memo:
1982 return memo[self]
1983 newRef = copy.copy(self)
1984 memo[self] = newRef
1985 newRef.simobj = simobj
1986 assert(isSimObject(newRef.simobj))
1987 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1988 return newRef
1989
1990 def unproxy(self, simobj):
1991 [el.unproxy(simobj) for el in self.elements]
1992
1993 def ccConnect(self):
1994 [el.ccConnect() for el in self.elements]
1995
1996# Port description object. Like a ParamDesc object, this represents a
1997# logical port in the SimObject class, not a particular port on a
1998# SimObject instance. The latter are represented by PortRef objects.
1999class Port(object):
2000 # Generate a PortRef for this port on the given SimObject with the
2001 # given name
2002 def makeRef(self, simobj):
2003 return PortRef(simobj, self.name, self.role)
2004
2005 # Connect an instance of this port (on the given SimObject with
2006 # the given name) with the port described by the supplied PortRef
2007 def connect(self, simobj, ref):
2008 self.makeRef(simobj).connect(ref)
2009
2010 # No need for any pre-declarations at the moment as we merely rely
2011 # on an unsigned int.
2012 def cxx_predecls(self, code):
2013 pass
2014
2015 def pybind_predecls(self, code):
2016 cls.cxx_predecls(self, code)
2017
2018 # Declare an unsigned int with the same name as the port, that
2019 # will eventually hold the number of connected ports (and thus the
2020 # number of elements for a VectorPort).
2021 def cxx_decl(self, code):
2022 code('unsigned int port_${{self.name}}_connection_count;')
2023
2024class MasterPort(Port):
2025 # MasterPort("description")
2026 def __init__(self, *args):
2027 if len(args) == 1:
2028 self.desc = args[0]
2029 self.role = 'MASTER'
2030 else:
2031 raise TypeError('wrong number of arguments')
2032
2033class SlavePort(Port):
2034 # SlavePort("description")
2035 def __init__(self, *args):
2036 if len(args) == 1:
2037 self.desc = args[0]
2038 self.role = 'SLAVE'
2039 else:
2040 raise TypeError('wrong number of arguments')
2041
2042# VectorPort description object. Like Port, but represents a vector
2043# of connections (e.g., as on a XBar).
2044class VectorPort(Port):
2045 def __init__(self, *args):
2046 self.isVec = True
2047
2048 def makeRef(self, simobj):
2049 return VectorPortRef(simobj, self.name, self.role)
2050
2051class VectorMasterPort(VectorPort):
2052 # VectorMasterPort("description")
2053 def __init__(self, *args):
2054 if len(args) == 1:
2055 self.desc = args[0]
2056 self.role = 'MASTER'
2057 VectorPort.__init__(self, *args)
2058 else:
2059 raise TypeError('wrong number of arguments')
2060
2061class VectorSlavePort(VectorPort):
2062 # VectorSlavePort("description")
2063 def __init__(self, *args):
2064 if len(args) == 1:
2065 self.desc = args[0]
2066 self.role = 'SLAVE'
2067 VectorPort.__init__(self, *args)
2068 else:
2069 raise TypeError('wrong number of arguments')
2070
2071# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2072# proxy objects (via set_param_desc()) so that proxy error messages
2073# make sense.
2074class PortParamDesc(object):
2075 __metaclass__ = Singleton
2076
2077 ptype_str = 'Port'
2078 ptype = Port
2079
2080baseEnums = allEnums.copy()
2081baseParams = allParams.copy()
2082
2083def clear():
2084 global allEnums, allParams
2085
2086 allEnums = baseEnums.copy()
2087 allParams = baseParams.copy()
2088
2089__all__ = ['Param', 'VectorParam',
2090 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2091 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2092 'Int32', 'UInt32', 'Int64', 'UInt64',
2093 'Counter', 'Addr', 'Tick', 'Percent',
2094 'TcpPort', 'UdpPort', 'EthernetAddr',
2095 'IpAddress', 'IpNetmask', 'IpWithPort',
2096 'MemorySize', 'MemorySize32',
2097 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2098 'NetworkBandwidth', 'MemoryBandwidth',
2099 'AddrRange',
2100 'MaxAddr', 'MaxTick', 'AllMemory',
2101 'Time',
2102 'NextEthernetAddr', 'NULL',
2103 'MasterPort', 'SlavePort',
2104 'VectorMasterPort', 'VectorSlavePort']
2105
2106import SimObject
1982 return memo[self]
1983 newRef = copy.copy(self)
1984 memo[self] = newRef
1985 newRef.simobj = simobj
1986 assert(isSimObject(newRef.simobj))
1987 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1988 return newRef
1989
1990 def unproxy(self, simobj):
1991 [el.unproxy(simobj) for el in self.elements]
1992
1993 def ccConnect(self):
1994 [el.ccConnect() for el in self.elements]
1995
1996# Port description object. Like a ParamDesc object, this represents a
1997# logical port in the SimObject class, not a particular port on a
1998# SimObject instance. The latter are represented by PortRef objects.
1999class Port(object):
2000 # Generate a PortRef for this port on the given SimObject with the
2001 # given name
2002 def makeRef(self, simobj):
2003 return PortRef(simobj, self.name, self.role)
2004
2005 # Connect an instance of this port (on the given SimObject with
2006 # the given name) with the port described by the supplied PortRef
2007 def connect(self, simobj, ref):
2008 self.makeRef(simobj).connect(ref)
2009
2010 # No need for any pre-declarations at the moment as we merely rely
2011 # on an unsigned int.
2012 def cxx_predecls(self, code):
2013 pass
2014
2015 def pybind_predecls(self, code):
2016 cls.cxx_predecls(self, code)
2017
2018 # Declare an unsigned int with the same name as the port, that
2019 # will eventually hold the number of connected ports (and thus the
2020 # number of elements for a VectorPort).
2021 def cxx_decl(self, code):
2022 code('unsigned int port_${{self.name}}_connection_count;')
2023
2024class MasterPort(Port):
2025 # MasterPort("description")
2026 def __init__(self, *args):
2027 if len(args) == 1:
2028 self.desc = args[0]
2029 self.role = 'MASTER'
2030 else:
2031 raise TypeError('wrong number of arguments')
2032
2033class SlavePort(Port):
2034 # SlavePort("description")
2035 def __init__(self, *args):
2036 if len(args) == 1:
2037 self.desc = args[0]
2038 self.role = 'SLAVE'
2039 else:
2040 raise TypeError('wrong number of arguments')
2041
2042# VectorPort description object. Like Port, but represents a vector
2043# of connections (e.g., as on a XBar).
2044class VectorPort(Port):
2045 def __init__(self, *args):
2046 self.isVec = True
2047
2048 def makeRef(self, simobj):
2049 return VectorPortRef(simobj, self.name, self.role)
2050
2051class VectorMasterPort(VectorPort):
2052 # VectorMasterPort("description")
2053 def __init__(self, *args):
2054 if len(args) == 1:
2055 self.desc = args[0]
2056 self.role = 'MASTER'
2057 VectorPort.__init__(self, *args)
2058 else:
2059 raise TypeError('wrong number of arguments')
2060
2061class VectorSlavePort(VectorPort):
2062 # VectorSlavePort("description")
2063 def __init__(self, *args):
2064 if len(args) == 1:
2065 self.desc = args[0]
2066 self.role = 'SLAVE'
2067 VectorPort.__init__(self, *args)
2068 else:
2069 raise TypeError('wrong number of arguments')
2070
2071# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2072# proxy objects (via set_param_desc()) so that proxy error messages
2073# make sense.
2074class PortParamDesc(object):
2075 __metaclass__ = Singleton
2076
2077 ptype_str = 'Port'
2078 ptype = Port
2079
2080baseEnums = allEnums.copy()
2081baseParams = allParams.copy()
2082
2083def clear():
2084 global allEnums, allParams
2085
2086 allEnums = baseEnums.copy()
2087 allParams = baseParams.copy()
2088
2089__all__ = ['Param', 'VectorParam',
2090 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2091 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2092 'Int32', 'UInt32', 'Int64', 'UInt64',
2093 'Counter', 'Addr', 'Tick', 'Percent',
2094 'TcpPort', 'UdpPort', 'EthernetAddr',
2095 'IpAddress', 'IpNetmask', 'IpWithPort',
2096 'MemorySize', 'MemorySize32',
2097 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2098 'NetworkBandwidth', 'MemoryBandwidth',
2099 'AddrRange',
2100 'MaxAddr', 'MaxTick', 'AllMemory',
2101 'Time',
2102 'NextEthernetAddr', 'NULL',
2103 'MasterPort', 'SlavePort',
2104 'VectorMasterPort', 'VectorSlavePort']
2105
2106import SimObject