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