1# Copyright (c) 2004-2006 The Regents of The University of Michigan 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright --- 127 unchanged lines hidden (view full) --- 136# that derive from SimObject are instantiated, and provides inherited 137# class behavior (just like a class controls how instances of that 138# class are instantiated, and provides inherited instance behavior). 139class MetaSimObject(type): 140 # Attributes that can be set only at initialization time 141 init_keywords = { 'abstract' : types.BooleanType, 142 'type' : types.StringType } 143 # Attributes that can be set any time |
144 keywords = { 'check' : types.FunctionType, 145 'cxx_type' : types.StringType, 146 'cxx_predecls' : types.ListType, 147 'swig_predecls' : types.ListType } |
148 149 # __new__ is called before __init__, and is where the statements 150 # in the body of the class definition get loaded into the class's 151 # __dict__. We intercept this to filter out parameter & port assignments 152 # and only allow "private" attributes to be passed to the base 153 # __new__ (starting with underscore). 154 def __new__(mcls, name, bases, dict): 155 # Copy "private" attributes, functions, and classes to the --- 66 unchanged lines hidden (view full) --- 222 # init-time-only keywords 223 elif cls.init_keywords.has_key(key): 224 cls._set_keyword(key, val, cls.init_keywords[key]) 225 226 # default: use normal path (ends up in __setattr__) 227 else: 228 setattr(cls, key, val) 229 |
230 cls.cxx_type = cls.type + '*' 231 # A forward class declaration is sufficient since we are just 232 # declaring a pointer. 233 cls.cxx_predecls = ['class %s;' % cls.type] 234 cls.swig_predecls = cls.cxx_predecls 235 |
236 def _set_keyword(cls, keyword, val, kwtype): 237 if not isinstance(val, kwtype): 238 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ 239 (keyword, type(val), kwtype) 240 if isinstance(val, types.FunctionType): 241 val = classmethod(val) 242 type.__setattr__(cls, keyword, val) 243 |
244 def _new_param(cls, name, pdesc): 245 # each param desc should be uniquely assigned to one variable 246 assert(not hasattr(pdesc, 'name')) 247 pdesc.name = name 248 cls._params[name] = pdesc 249 if hasattr(pdesc, 'default'): 250 setattr(cls, name, pdesc.default) |
251 252 # Set attribute (called on foo.attr = value when foo is an 253 # instance of class cls). 254 def __setattr__(cls, attr, value): 255 # normal processing for private attributes 256 if attr.startswith('_'): 257 type.__setattr__(cls, attr, value) 258 return --- 31 unchanged lines hidden (view full) --- 290 291 def __getattr__(cls, attr): 292 if cls._values.has_key(attr): 293 return cls._values[attr] 294 295 raise AttributeError, \ 296 "object '%s' has no attribute '%s'" % (cls.__name__, attr) 297 |
298 def __str__(cls): 299 return cls.__name__ 300 301 def cxx_decl(cls): 302 code = "#ifndef __PARAMS__%s\n#define __PARAMS__%s\n\n" % (cls, cls) 303 304 if str(cls) != 'SimObject': 305 base = cls.__bases__[0].type 306 else: 307 base = None 308 309 # The 'dict' attribute restricts us to the params declared in 310 # the object itself, not including inherited params (which 311 # will also be inherited from the base class's param struct 312 # here). 313 params = cls._params.dict.values() 314 try: 315 ptypes = [p.ptype for p in params] 316 except: 317 print cls, p, p.ptype_str 318 print params 319 raise 320 321 # get a list of lists of predeclaration lines 322 predecls = [p.cxx_predecls() for p in params] 323 # flatten 324 predecls = reduce(lambda x,y:x+y, predecls, []) 325 # remove redundant lines 326 predecls2 = [] 327 for pd in predecls: 328 if pd not in predecls2: 329 predecls2.append(pd) 330 predecls2.sort() 331 code += "\n".join(predecls2) 332 code += "\n\n"; 333 334 if base: 335 code += '#include "params/%s.hh"\n\n' % base 336 337 # Generate declarations for locally defined enumerations. 338 enum_ptypes = [t for t in ptypes if issubclass(t, Enum)] 339 if enum_ptypes: 340 code += "\n".join([t.cxx_decl() for t in enum_ptypes]) 341 code += "\n\n" 342 343 # now generate the actual param struct 344 code += "struct %sParams" % cls 345 if base: 346 code += " : public %sParams" % base 347 code += " {\n" 348 decls = [p.cxx_decl() for p in params] 349 decls.sort() 350 code += "".join([" %s\n" % d for d in decls]) 351 code += "};\n" 352 353 # close #ifndef __PARAMS__* guard 354 code += "\n#endif\n" 355 return code 356 357 def swig_decl(cls): 358 359 code = '%%module %sParams\n' % cls 360 361 if str(cls) != 'SimObject': 362 base = cls.__bases__[0].type 363 else: 364 base = None 365 366 # The 'dict' attribute restricts us to the params declared in 367 # the object itself, not including inherited params (which 368 # will also be inherited from the base class's param struct 369 # here). 370 params = cls._params.dict.values() 371 ptypes = [p.ptype for p in params] 372 373 # get a list of lists of predeclaration lines 374 predecls = [p.swig_predecls() for p in params] 375 # flatten 376 predecls = reduce(lambda x,y:x+y, predecls, []) 377 # remove redundant lines 378 predecls2 = [] 379 for pd in predecls: 380 if pd not in predecls2: 381 predecls2.append(pd) 382 predecls2.sort() 383 code += "\n".join(predecls2) 384 code += "\n\n"; 385 386 if base: 387 code += '%%import "python/m5/swig/%sParams.i"\n\n' % base 388 389 code += '%{\n' 390 code += '#include "params/%s.hh"\n' % cls 391 code += '%}\n\n' 392 code += '%%include "params/%s.hh"\n\n' % cls 393 394 return code 395 |
396# The SimObject class is the root of the special hierarchy. Most of 397# the code in this class deals with the configuration hierarchy itself 398# (parent/child node relationships). 399class SimObject(object): 400 # Specify metaclass. Any class inheriting from SimObject will 401 # get this metaclass. 402 __metaclass__ = MetaSimObject |
403 type = 'SimObject' |
404 |
405 name = Param.String("Object name") 406 |
407 # Initialize new instance. For objects with SimObject-valued 408 # children, we need to recursively clone the classes represented 409 # by those param values as well in a consistent "deep copy"-style 410 # fashion. That is, we want to make sure that each instance is 411 # cloned only once, and that if there are multiple references to 412 # the same original object, we end up with the corresponding 413 # cloned references all pointing to the same cloned instance. 414 def __init__(self, **kwargs): --- 488 unchanged lines hidden (view full) --- 903# MetaSimObject._new_param()); after that point they aren't used. 904# 905##################################################################### 906 907# Dummy base class to identify types that are legitimate for SimObject 908# parameters. 909class ParamValue(object): 910 |
911 cxx_predecls = [] 912 swig_predecls = [] 913 |
914 # default for printing to .ini file is regular string conversion. 915 # will be overridden in some cases 916 def ini_str(self): 917 return str(self) 918 919 # allows us to blithely call unproxy() on things without checking 920 # if they're really proxies or not 921 def unproxy(self, base): --- 54 unchanged lines hidden (view full) --- 976 # we're just assigning a null pointer 977 return value 978 if isinstance(value, self.ptype): 979 return value 980 if isNullPointer(value) and issubclass(self.ptype, SimObject): 981 return value 982 return self.ptype(value) 983 |
984 def cxx_predecls(self): 985 return self.ptype.cxx_predecls 986 987 def swig_predecls(self): 988 return self.ptype.swig_predecls 989 990 def cxx_decl(self): 991 return '%s %s;' % (self.ptype.cxx_type, self.name) 992 |
993# Vector-valued parameter description. Just like ParamDesc, except 994# that the value is a vector (list) of the specified type instead of a 995# single value. 996 997class VectorParamValue(list): 998 def ini_str(self): 999 return ' '.join([v.ini_str() for v in self]) 1000 --- 16 unchanged lines hidden (view full) --- 1017 return SimObjVector(tmp_list) 1018 else: 1019 return VectorParamValue(tmp_list) 1020 else: 1021 # singleton: leave it be (could coerce to a single-element 1022 # list here, but for some historical reason we don't... 1023 return ParamDesc.convert(self, value) 1024 |
1025 def cxx_predecls(self): 1026 return ['#include <vector>'] + self.ptype.cxx_predecls |
1027 |
1028 def swig_predecls(self): 1029 return ['%include "std_vector.i"'] + self.ptype.swig_predecls 1030 1031 def cxx_decl(self): 1032 return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name) 1033 |
1034class ParamFactory(object): 1035 def __init__(self, param_desc_class, ptype_str = None): 1036 self.param_desc_class = param_desc_class 1037 self.ptype_str = ptype_str 1038 1039 def __getattr__(self, attr): 1040 if self.ptype_str: 1041 attr = self.ptype_str + '.' + attr --- 13 unchanged lines hidden (view full) --- 1055 # if name isn't defined yet, assume it's a SimObject, and 1056 # try to resolve it later 1057 pass 1058 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 1059 1060Param = ParamFactory(ParamDesc) 1061VectorParam = ParamFactory(VectorParamDesc) 1062 |
1063# String-valued parameter. Just mixin the ParamValue class 1064# with the built-in str class. 1065class String(ParamValue,str): 1066 cxx_type = 'std::string' 1067 cxx_predecls = ['#include <string>'] 1068 swig_predecls = ['%include "std_string.i"\n' + 1069 '%apply const std::string& {std::string *};'] 1070 pass 1071 |
1072##################################################################### 1073# 1074# Parameter Types 1075# 1076# Though native Python types could be used to specify parameter types 1077# (the 'ptype' field of the Param and VectorParam classes), it's more 1078# flexible to define our own set of types. This gives us more control 1079# over how Python expressions are converted to values (via the --- 32 unchanged lines hidden (view full) --- 1112 return newobj 1113 1114 def __sub__(self, other): 1115 newobj = self.__class__(self) 1116 newobj.value -= other 1117 newobj._check() 1118 return newobj 1119 |
1120# Metaclass for bounds-checked integer parameters. See CheckedInt. 1121class CheckedIntType(type): 1122 def __init__(cls, name, bases, dict): 1123 super(CheckedIntType, cls).__init__(name, bases, dict) 1124 1125 # CheckedInt is an abstract base class, so we actually don't 1126 # want to do any processing on it... the rest of this code is 1127 # just for classes that derive from CheckedInt. 1128 if name == 'CheckedInt': 1129 return 1130 |
1131 if not cls.cxx_predecls: 1132 # most derived types require this, so we just do it here once 1133 cls.cxx_predecls = ['#include "sim/host.hh"'] 1134 1135 if not cls.swig_predecls: 1136 # most derived types require this, so we just do it here once 1137 cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 1138 '%import "sim/host.hh"'] 1139 |
1140 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 1141 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 1142 panic("CheckedInt subclass %s must define either\n" \ 1143 " 'min' and 'max' or 'size' and 'unsigned'\n" \ 1144 % name); 1145 if cls.unsigned: 1146 cls.min = 0 1147 cls.max = 2 ** cls.size - 1 --- 15 unchanged lines hidden (view full) --- 1163 1164 def __init__(self, value): 1165 if isinstance(value, str): 1166 self.value = toInteger(value) 1167 elif isinstance(value, (int, long, float)): 1168 self.value = long(value) 1169 self._check() 1170 |
1171class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 1172class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True |
1173 |
1174class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 1175class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 1176class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 1177class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 1178class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 1179class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 1180class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 1181class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True |
1182 |
1183class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 1184class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 1185class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 1186class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True |
1187 |
1188class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 |
1189 1190class Float(ParamValue, float): 1191 pass 1192 1193class MemorySize(CheckedInt): |
1194 cxx_type = 'uint64_t' |
1195 size = 64 1196 unsigned = True 1197 def __init__(self, value): 1198 if isinstance(value, MemorySize): 1199 self.value = value.value 1200 else: 1201 self.value = toMemorySize(value) 1202 self._check() --- 4 unchanged lines hidden (view full) --- 1207 def __init__(self, value): 1208 if isinstance(value, MemorySize): 1209 self.value = value.value 1210 else: 1211 self.value = toMemorySize(value) 1212 self._check() 1213 1214class Addr(CheckedInt): |
1215 cxx_type = 'Addr' 1216 cxx_predecls = ['#include "targetarch/isa_traits.hh"'] |
1217 size = 64 1218 unsigned = True 1219 def __init__(self, value): 1220 if isinstance(value, Addr): 1221 self.value = value.value 1222 else: 1223 try: 1224 self.value = toMemorySize(value) 1225 except TypeError: 1226 self.value = long(value) 1227 self._check() 1228 |
1229 1230class MetaRange(type): 1231 def __init__(cls, name, bases, dict): 1232 super(MetaRange, cls).__init__(name, bases, dict) 1233 if name == 'Range': 1234 return 1235 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 1236 cls.cxx_predecls = \ 1237 ['#include "base/range.hh"'] + cls.type.cxx_predecls 1238 1239class Range(ParamValue): 1240 __metaclass__ = MetaRange 1241 type = Int # default; can be overridden in subclasses 1242 def __init__(self, *args, **kwargs): 1243 def handle_kwargs(self, kwargs): 1244 if 'end' in kwargs: 1245 self.second = self.type(kwargs.pop('end')) 1246 elif 'size' in kwargs: 1247 self.second = self.first + self.type(kwargs.pop('size')) - 1 1248 else: 1249 raise TypeError, "Either end or size must be specified" 1250 1251 if len(args) == 0: 1252 self.first = self.type(kwargs.pop('start')) 1253 handle_kwargs(self, kwargs) 1254 1255 elif len(args) == 1: 1256 if kwargs: 1257 self.first = self.type(args[0]) 1258 handle_kwargs(self, kwargs) 1259 elif isinstance(args[0], Range): 1260 self.first = self.type(args[0].first) 1261 self.second = self.type(args[0].second) 1262 else: 1263 self.first = self.type(0) 1264 self.second = self.type(args[0]) - 1 1265 1266 elif len(args) == 2: 1267 self.first = self.type(args[0]) 1268 self.second = self.type(args[1]) 1269 else: 1270 raise TypeError, "Too many arguments specified" 1271 1272 if kwargs: 1273 raise TypeError, "too many keywords: %s" % kwargs.keys() 1274 1275 def __str__(self): 1276 return '%s:%s' % (self.first, self.second) 1277 |
1278class AddrRange(Range): 1279 type = Addr 1280 |
1281class TickRange(Range): 1282 type = Tick |
1283 1284# Boolean parameter type. Python doesn't let you subclass bool, since 1285# it doesn't want to let you create multiple instances of True and 1286# False. Thus this is a little more complicated than String. 1287class Bool(ParamValue): |
1288 cxx_type = 'bool' |
1289 def __init__(self, value): 1290 try: 1291 self.value = toBool(value) 1292 except TypeError: 1293 self.value = bool(value) 1294 1295 def __str__(self): 1296 return str(self.value) --- 18 unchanged lines hidden (view full) --- 1315class NextEthernetAddr(object): 1316 addr = "00:90:00:00:00:01" 1317 1318 def __init__(self, inc = 1): 1319 self.value = NextEthernetAddr.addr 1320 NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) 1321 1322class EthernetAddr(ParamValue): |
1323 cxx_type = 'Net::EthAddr' 1324 cxx_predecls = ['#include "base/inet.hh"'] 1325 swig_predecls = ['class Net::EthAddr;'] |
1326 def __init__(self, value): 1327 if value == NextEthernetAddr: 1328 self.value = value 1329 return 1330 1331 if not isinstance(value, str): 1332 raise TypeError, "expected an ethernet address and didn't get one" 1333 --- 80 unchanged lines hidden (view full) --- 1414 # build string->value map from vals sequence 1415 cls.map = {} 1416 for idx,val in enumerate(cls.vals): 1417 cls.map[val] = idx 1418 else: 1419 raise TypeError, "Enum-derived class must define "\ 1420 "attribute 'map' or 'vals'" 1421 |
1422 cls.cxx_type = name + '::Enum' 1423 |
1424 super(MetaEnum, cls).__init__(name, bases, init_dict) 1425 |
1426 # Generate C++ class declaration for this enum type. 1427 # Note that we wrap the enum in a class/struct to act as a namespace, 1428 # so that the enum strings can be brief w/o worrying about collisions. 1429 def cxx_decl(cls): 1430 s = 'struct %s {\n enum Enum {\n ' % cls.__name__ |
1431 s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) |
1432 s += '\n };\n};\n' |
1433 return s 1434 1435# Base class for enum types. 1436class Enum(ParamValue): 1437 __metaclass__ = MetaEnum 1438 vals = [] 1439 1440 def __init__(self, value): --- 35 unchanged lines hidden (view full) --- 1476 try: 1477 return 1 / toFrequency(value) 1478 except ValueError: 1479 pass # fall through 1480 raise ValueError, "Invalid Frequency/Latency value '%s'" % value 1481 1482 1483class Latency(NumericParamValue): |
1484 cxx_type = 'Tick' 1485 cxx_predecls = ['#include "sim/host.hh"'] 1486 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 1487 '%import "sim/host.hh"'] |
1488 def __init__(self, value): 1489 self.value = getLatency(value) 1490 1491 def __getattr__(self, attr): 1492 if attr in ('latency', 'period'): 1493 return self 1494 if attr == 'frequency': 1495 return Frequency(self) 1496 raise AttributeError, "Latency object has no attribute '%s'" % attr 1497 1498 # convert latency to ticks 1499 def ini_str(self): 1500 return str(tick_check(self.value * ticks_per_sec)) 1501 1502class Frequency(NumericParamValue): |
1503 cxx_type = 'Tick' 1504 cxx_predecls = ['#include "sim/host.hh"'] 1505 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 1506 '%import "sim/host.hh"'] |
1507 def __init__(self, value): 1508 self.value = 1 / getLatency(value) 1509 1510 def __getattr__(self, attr): 1511 if attr == 'frequency': 1512 return self 1513 if attr in ('latency', 'period'): 1514 return Latency(self) 1515 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1516 1517 # convert frequency to ticks per period 1518 def ini_str(self): 1519 return self.period.ini_str() 1520 1521# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz). 1522# We can't inherit from Frequency because we don't want it to be directly 1523# assignable to a regular Frequency parameter. 1524class RootClock(ParamValue): |
1525 cxx_type = 'Tick' 1526 cxx_predecls = ['#include "sim/host.hh"'] 1527 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 1528 '%import "sim/host.hh"'] |
1529 def __init__(self, value): 1530 self.value = 1 / getLatency(value) 1531 1532 def __getattr__(self, attr): 1533 if attr == 'frequency': 1534 return Frequency(self) 1535 if attr in ('latency', 'period'): 1536 return Latency(self) 1537 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1538 1539 def ini_str(self): 1540 return str(tick_check(self.value)) 1541 1542# A generic frequency and/or Latency value. Value is stored as a latency, 1543# but to avoid ambiguity this object does not support numeric ops (* or /). 1544# An explicit conversion to a Latency or Frequency must be made first. 1545class Clock(ParamValue): |
1546 cxx_type = 'Tick' 1547 cxx_predecls = ['#include "sim/host.hh"'] 1548 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 1549 '%import "sim/host.hh"'] |
1550 def __init__(self, value): 1551 self.value = getLatency(value) 1552 1553 def __getattr__(self, attr): 1554 if attr == 'frequency': 1555 return Frequency(self) 1556 if attr in ('latency', 'period'): 1557 return Latency(self) 1558 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1559 1560 def ini_str(self): 1561 return self.period.ini_str() 1562 1563class NetworkBandwidth(float,ParamValue): |
1564 cxx_type = 'float' |
1565 def __new__(cls, value): 1566 val = toNetworkBandwidth(value) / 8.0 1567 return super(cls, NetworkBandwidth).__new__(cls, val) 1568 1569 def __str__(self): 1570 return str(self.val) 1571 1572 def ini_str(self): 1573 return '%f' % (ticks_per_sec / float(self)) 1574 1575class MemoryBandwidth(float,ParamValue): |
1576 cxx_type = 'float' |
1577 def __new__(self, value): 1578 val = toMemoryBandwidth(value) 1579 return super(cls, MemoryBandwidth).__new__(cls, val) 1580 1581 def __str__(self): 1582 return str(self.val) 1583 1584 def ini_str(self): --- 119 unchanged lines hidden (view full) --- 1704 'Enum', 'Bool', 'String', 'Float', 1705 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1706 'Int32', 'UInt32', 'Int64', 'UInt64', 1707 'Counter', 'Addr', 'Tick', 'Percent', 1708 'TcpPort', 'UdpPort', 'EthernetAddr', 1709 'MemorySize', 'MemorySize32', 1710 'Latency', 'Frequency', 'RootClock', 'Clock', 1711 'NetworkBandwidth', 'MemoryBandwidth', |
1712 'Range', 'AddrRange', 'TickRange', 1713 'MaxAddr', 'MaxTick', 'AllMemory', |
1714 'Null', 'NULL', 1715 'NextEthernetAddr', 1716 'Port', 'VectorPort'] 1717 |