2 * Copyright (c) 2003 The Regents of The University of Michigan
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <stdio.h> // for sscanf()
37 #include "sim/param.hh"
38 #include "sim/sim_object.hh"
39 #include "base/inifile.hh"
40 #include "sim/configfile.hh"
41 #include "sim/config_node.hh"
42 #include "base/misc.hh"
43 #include "base/str.hh"
44 #include "base/trace.hh"
49 ////////////////////////////////////////////////////////////////////////
51 // BaseParam member definitions
53 ////////////////////////////////////////////////////////////////////////
56 BaseParam::die(const string
&err
) const
58 context
->printErrorProlog(cerr
);
59 cerr
<< " parameter '" << name
<< "': "
65 ////////////////////////////////////////////////////////////////////////
67 // Param<T> and VectorParam<T> member definitions
69 // We implement parsing & displaying values for various parameter
70 // types T using a set of overloaded functions:
72 // - parseParam(string s, T &value) parses s into value
73 // - showParam(ostream &os, T &value) displays value on os
75 // By making these independent functions, we can reuse the same code
76 // for type T in both Param<T> and VectorParam<T>.
78 // For enum types, the parseParam function requires additional
79 // arguments, in which case we must specialize the Param<T>::parse and
80 // VectorParam<T>::parse calls as well.
82 // Type-specific instances come first, followed by more generic
83 // templated versions and their instantiations.
85 ////////////////////////////////////////////////////////////////////////
88 // The base implementations use to_number for parsing and '<<' for
89 // displaying, suitable for integer types.
93 parseParam(const string
&s
, T
&value
)
95 return to_number(s
, value
);
100 showParam(ostream
&os
, T
const &value
)
106 // Template specializations:
107 // - char (8-bit integer)
108 // - floating-point types
113 // Treat 8-bit ints (chars) as ints on output, not as chars
116 showParam(ostream
&os
, const char &value
)
124 showParam(ostream
&os
, const unsigned char &value
)
126 os
<< (unsigned int)value
;
130 // Use sscanf() for FP types as to_number() only handles integers
133 parseParam(const string
&s
, float &value
)
135 return (sscanf(s
.c_str(), "%f", &value
) == 1);
140 parseParam(const string
&s
, double &value
)
142 return (sscanf(s
.c_str(), "%lf", &value
) == 1);
145 // Be flexible about what we take for bool
148 parseParam(const string
&s
, bool &value
)
150 const string
&lower
= to_lower(s
);
152 if (lower
== "true" || lower
== "t" || lower
== "yes" || lower
== "y") {
157 if (lower
== "false" || lower
== "f" || lower
== "no" || lower
== "n") {
165 // Display bools as strings
168 showParam(ostream
&os
, const bool &value
)
170 os
<< (value
? "true" : "false");
174 // String requires no processing to speak of
177 parseParam(const string
&s
, string
&value
)
184 // End of parseParam/showParam definitions. Now we move on to
185 // incorporate them into the Param/VectorParam parse() and showValue()
189 // These definitions for Param<T>::parse and VectorParam<T>::parse
190 // work for any type for which parseParam() takes only two arguments
191 // (i.e., all the fundamental types like int, bool, etc.), thanks to
195 Param
<T
>::parse(const string
&s
)
197 if (parseParam(s
, value
)) {
201 string
err("could not parse \"");
212 VectorParam
<T
>::parse(const string
&s
)
214 vector
<string
> tokens
;
216 tokenize(tokens
, s
, ' ');
218 value
.resize(tokens
.size());
220 for (int i
= 0; i
< tokens
.size(); i
++) {
221 // need to parse into local variable to handle vector<bool>,
222 // for which operator[] returns a special reference class
223 // that's not the same as 'bool&', (since it's a packed
226 if (!parseParam(tokens
[i
], scalar_value
)) {
227 string
err("could not parse \"");
235 // assign parsed value to vector
236 value
[i
] = scalar_value
;
242 // These definitions for Param<T>::showValue() and
243 // VectorParam<T>::showValue() work for any type where showParam()
244 // takes only two arguments (i.e., everything but the SimpleEnum and
245 // MappedEnum classes).
248 Param
<T
>::showValue(ostream
&os
) const
250 showParam(os
, value
);
255 VectorParam
<T
>::showValue(ostream
&os
) const
257 for (int i
= 0; i
< value
.size(); i
++) {
261 showParam(os
, value
[i
]);
267 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
268 void Param<type>::showType(ostream &os) const { os << typestr; } \
269 void VectorParam<type>::showType(ostream &os) const { \
270 os << "vector of " << typestr; \
272 template Param<type>; \
273 template VectorParam<type>;
276 // instantiate all four methods (parse/show, scalar/vector) for basic
277 // types that can use the above templates
278 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
279 template bool parseParam<type>(const string &s, type &value); \
280 template void showParam<type>(ostream &os, type const &value); \
281 template void Param<type>::parse(const string &); \
282 template void VectorParam<type>::parse(const string &); \
283 template void Param<type>::showValue(ostream &) const; \
284 template void VectorParam<type>::showValue(ostream &) const; \
285 void Param<type>::showType(ostream &os) const { os << typestr; } \
286 void VectorParam<type>::showType(ostream &os) const { \
287 os << "vector of " << typestr; \
291 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
292 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
293 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
294 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
295 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
296 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
297 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
298 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
299 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
300 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
302 INSTANTIATE_PARAM_TEMPLATES(float, "float")
303 INSTANTIATE_PARAM_TEMPLATES(double, "double")
305 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
306 INSTANTIATE_PARAM_TEMPLATES(string
, "string")
308 #undef INSTANTIATE_PARAM_TEMPLATES
311 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
312 // showValue(), and showType() methods.
316 // SimpleEnumParam & SimpleEnumVectorParam
319 parseEnumParam(const char *const *map
, const int num_values
,
320 const string
&s
, int &value
)
322 for (int i
= 0; i
< num_values
; ++i
) {
333 showEnumParam(ostream
&os
,
334 const char *const *map
, const int num_values
,
337 assert(0 <= value
&& value
< num_values
);
342 showEnumType(ostream
&os
,
343 const char *const *map
, const int num_values
)
346 for (int i
= 1; i
< num_values
; ++i
)
354 // MappedEnumParam & MappedEnumVectorParam
357 parseEnumParam(const EnumParamMap
*map
, const int num_values
,
358 const string
&s
, int &value
)
360 for (int i
= 0; i
< num_values
; ++i
) {
361 if (s
== map
[i
].name
) {
362 value
= map
[i
].value
;
371 showEnumParam(ostream
&os
,
372 const EnumParamMap
*map
, const int num_values
,
375 for (int i
= 0; i
< num_values
; ++i
) {
376 if (value
== map
[i
].value
) {
382 // if we can't find a reverse mapping just print the int value
387 showEnumType(ostream
&os
,
388 const EnumParamMap
*map
, const int num_values
)
390 os
<< "{" << map
[0].name
;
391 for (int i
= 1; i
< num_values
; ++i
)
392 os
<< "," << map
[i
].name
;
400 EnumParam
<Map
>::parse(const string
&s
)
402 if (parseEnumParam(map
, num_values
, s
, value
)) {
405 string
err("no match for enum string \"");
416 EnumVectorParam
<Map
>::parse(const string
&s
)
418 vector
<string
> tokens
;
420 tokenize(tokens
, s
, ' ');
422 value
.resize(tokens
.size());
424 for (int i
= 0; i
< tokens
.size(); i
++) {
425 if (!parseEnumParam(map
, num_values
, tokens
[i
], value
[i
])) {
426 string
err("no match for enum string \"");
440 EnumParam
<Map
>::showValue(ostream
&os
) const
442 showEnumParam(os
, map
, num_values
, value
);
447 EnumVectorParam
<Map
>::showValue(ostream
&os
) const
449 for (int i
= 0; i
< value
.size(); i
++) {
453 showEnumParam(os
, map
, num_values
, value
[i
]);
459 EnumParam
<Map
>::showType(ostream
&os
) const
461 showEnumType(os
, map
, num_values
);
466 EnumVectorParam
<Map
>::showType(ostream
&os
) const
469 showEnumType(os
, map
, num_values
);
472 template EnumParam
<const char *>;
473 template EnumVectorParam
<const char *>;
475 template EnumParam
<EnumParamMap
>;
476 template EnumVectorParam
<EnumParamMap
>;
478 ////////////////////////////////////////////////////////////////////////
480 // SimObjectBaseParam methods
482 ////////////////////////////////////////////////////////////////////////
485 parseSimObjectParam(ParamContext
*context
, const string
&s
, SimObject
*&value
)
489 if (to_lower(s
) == "null") {
490 // explicitly set to null by user; assume that's OK
494 obj
= context
->resolveSimObject(s
);
506 SimObjectBaseParam::showValue(ostream
&os
, SimObject
*value
) const
508 os
<< (value
? value
->name() : "null");
512 SimObjectBaseParam::parse(const string
&s
, SimObject
*&value
)
514 if (parseSimObjectParam(context
, s
, value
)) {
518 string
err("could not resolve object name \"");
528 SimObjectBaseParam::parse(const string
&s
, vector
<SimObject
*>&value
)
530 vector
<string
> tokens
;
532 tokenize(tokens
, s
, ' ');
534 value
.resize(tokens
.size());
536 for (int i
= 0; i
< tokens
.size(); i
++) {
537 if (!parseSimObjectParam(context
, tokens
[i
], value
[i
])) {
538 string
err("could not resolve object name \"");
550 ////////////////////////////////////////////////////////////////////////
552 // ParamContext member definitions
554 ////////////////////////////////////////////////////////////////////////
556 list
<ParamContext
*> *ParamContext::ctxList
= NULL
;
558 ParamContext::ParamContext(const string
&_iniSection
, bool noAutoParse
)
559 : iniFilePtr(NULL
), // initialized on call to parseParams()
560 iniSection(_iniSection
), paramList(NULL
)
564 ctxList
= new list
<ParamContext
*>();
566 (*ctxList
).push_back(this);
572 ParamContext::addParam(BaseParam
*param
)
574 getParamList()->push_back(param
);
579 ParamContext::parseParams(IniFile
&iniFile
)
581 iniFilePtr
= &iniFile
; // set object member
583 ParamList::iterator i
;
585 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
588 if (iniFile
.findDefault(iniSection
, (*i
)->name
, string_value
)) {
589 (*i
)->parse(string_value
);
595 // Check parameter values for validity & consistency. Default
596 // implementation is no-op; derive subclass & override to add
597 // actual functionality here.
599 ParamContext::checkParams()
605 // Clean up context-related objects at end of execution. Default
606 // implementation is no-op; derive subclass & override to add actual
607 // functionality here.
609 ParamContext::cleanup()
616 ParamContext::describeParams(ostream
&os
)
618 ParamList::iterator i
;
620 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
623 os
<< p
->name
<< " (";
625 os
<< "): " << p
->description
<< "\n";
632 ParamContext::showParams(ostream
&os
)
634 ParamList::iterator i
;
636 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
640 os
<< p
->name
<< "=";
645 os
<< "// "<< p
->name
<< " not specified" << endl
;
652 ParamContext::printErrorProlog(ostream
&os
)
654 os
<< "Parameter error in section [" << iniSection
<< "]: " << endl
;
658 // Resolve an object name to a SimObject pointer. The object will be
659 // created as a side-effect if necessary. If the name contains a
660 // colon (e.g., "iq:IQ"), then the object is local (invisible to
661 // outside this context). If there is no colon, the name needs to be
662 // resolved through the configuration hierarchy (only possible for
663 // SimObjectBuilder objects, which return non-NULL for configNode()).
666 ParamContext::resolveSimObject(const string
&_name
)
669 string::size_type i
= _name
.find(':');
671 if (i
!= string::npos
) {
672 // colon found: local object
673 // add as child to current node and create it
674 name
= _name
.substr(0, i
);
675 string objConfigClassName
= _name
.substr(i
+ 1);
676 getConfigNode()->addChild(name
, objConfigClassName
);
678 ConfigNode
*n
= getConfigNode();
679 return n
? n
->resolveSimObject(name
) : NULL
;
684 // static method: call parseParams() on all registered contexts
687 ParamContext::parseAllContexts(IniFile
&iniFile
)
689 list
<ParamContext
*>::iterator iter
;
691 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
692 ParamContext
*pc
= *iter
;
694 pc
->parseParams(iniFile
);
700 // static method: call checkParams() on all registered contexts
703 ParamContext::checkAllContexts()
705 list
<ParamContext
*>::iterator iter
;
707 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
708 ParamContext
*pc
= *iter
;
716 // static method: call showParams() on all registered contexts
719 ParamContext::showAllContexts(ostream
&os
)
721 list
<ParamContext
*>::iterator iter
;
723 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
724 ParamContext
*pc
= *iter
;
726 os
<< "[" << pc
->iniSection
<< "]" << endl
;
734 // static method: call cleanup() on all registered contexts
737 ParamContext::cleanupAllContexts()
739 list
<ParamContext
*>::iterator iter
;
741 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
742 ParamContext
*pc
= *iter
;
750 // static method: call describeParams() on all registered contexts
753 ParamContext::describeAllContexts(ostream
&os
)
755 list
<ParamContext
*>::iterator iter
;
757 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
758 ParamContext
*pc
= *iter
;
760 os
<< "[" << pc
->iniSection
<< "]\n";
761 pc
->describeParams(os
);