2 * Copyright (c) 2002-2004 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
&ls
= to_lower(s
);
152 if (ls
== "true" || ls
== "t" || ls
== "yes" || ls
== "y" || ls
== "1") {
157 if (ls
== "false" || ls
== "f" || ls
== "no" || ls
== "n" || ls
== "0") {
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
)
219 vector
<string
> tokens
;
221 tokenize(tokens
, s
, ' ');
223 value
.resize(tokens
.size());
225 for (int i
= 0; i
< tokens
.size(); i
++) {
226 // need to parse into local variable to handle vector<bool>,
227 // for which operator[] returns a special reference class
228 // that's not the same as 'bool&', (since it's a packed
231 if (!parseParam(tokens
[i
], scalar_value
)) {
232 string
err("could not parse \"");
240 // assign parsed value to vector
241 value
[i
] = scalar_value
;
247 // These definitions for Param<T>::showValue() and
248 // VectorParam<T>::showValue() work for any type where showParam()
249 // takes only two arguments (i.e., everything but the SimpleEnum and
250 // MappedEnum classes).
253 Param
<T
>::showValue(ostream
&os
) const
255 showParam(os
, value
);
260 VectorParam
<T
>::showValue(ostream
&os
) const
262 for (int i
= 0; i
< value
.size(); i
++) {
266 showParam(os
, value
[i
]);
272 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
273 void Param<type>::showType(ostream &os) const { os << typestr; } \
274 void VectorParam<type>::showType(ostream &os) const { \
275 os << "vector of " << typestr; \
277 template Param<type>; \
278 template VectorParam<type>;
281 // instantiate all four methods (parse/show, scalar/vector) for basic
282 // types that can use the above templates
283 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
284 template bool parseParam<type>(const string &s, type &value); \
285 template void showParam<type>(ostream &os, type const &value); \
286 template void Param<type>::parse(const string &); \
287 template void VectorParam<type>::parse(const string &); \
288 template void Param<type>::showValue(ostream &) const; \
289 template void VectorParam<type>::showValue(ostream &) const; \
290 void Param<type>::showType(ostream &os) const { os << typestr; } \
291 void VectorParam<type>::showType(ostream &os) const { \
292 os << "vector of " << typestr; \
296 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
297 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
298 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
299 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
300 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
301 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
302 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
303 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
304 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
305 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
307 INSTANTIATE_PARAM_TEMPLATES(float, "float")
308 INSTANTIATE_PARAM_TEMPLATES(double, "double")
310 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
311 INSTANTIATE_PARAM_TEMPLATES(string
, "string")
313 #undef INSTANTIATE_PARAM_TEMPLATES
316 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
317 // showValue(), and showType() methods.
321 // SimpleEnumParam & SimpleEnumVectorParam
324 parseEnumParam(const char *const *map
, const int num_values
,
325 const string
&s
, int &value
)
327 for (int i
= 0; i
< num_values
; ++i
) {
338 showEnumParam(ostream
&os
,
339 const char *const *map
, const int num_values
,
342 assert(0 <= value
&& value
< num_values
);
347 showEnumType(ostream
&os
,
348 const char *const *map
, const int num_values
)
351 for (int i
= 1; i
< num_values
; ++i
)
359 // MappedEnumParam & MappedEnumVectorParam
362 parseEnumParam(const EnumParamMap
*map
, const int num_values
,
363 const string
&s
, int &value
)
365 for (int i
= 0; i
< num_values
; ++i
) {
366 if (s
== map
[i
].name
) {
367 value
= map
[i
].value
;
376 showEnumParam(ostream
&os
,
377 const EnumParamMap
*map
, const int num_values
,
380 for (int i
= 0; i
< num_values
; ++i
) {
381 if (value
== map
[i
].value
) {
387 // if we can't find a reverse mapping just print the int value
392 showEnumType(ostream
&os
,
393 const EnumParamMap
*map
, const int num_values
)
395 os
<< "{" << map
[0].name
;
396 for (int i
= 1; i
< num_values
; ++i
)
397 os
<< "," << map
[i
].name
;
405 EnumParam
<Map
>::parse(const string
&s
)
407 if (parseEnumParam(map
, num_values
, s
, value
)) {
410 string
err("no match for enum string \"");
421 EnumVectorParam
<Map
>::parse(const string
&s
)
423 vector
<string
> tokens
;
425 tokenize(tokens
, s
, ' ');
427 value
.resize(tokens
.size());
429 for (int i
= 0; i
< tokens
.size(); i
++) {
430 if (!parseEnumParam(map
, num_values
, tokens
[i
], value
[i
])) {
431 string
err("no match for enum string \"");
445 EnumParam
<Map
>::showValue(ostream
&os
) const
447 showEnumParam(os
, map
, num_values
, value
);
452 EnumVectorParam
<Map
>::showValue(ostream
&os
) const
454 for (int i
= 0; i
< value
.size(); i
++) {
458 showEnumParam(os
, map
, num_values
, value
[i
]);
464 EnumParam
<Map
>::showType(ostream
&os
) const
466 showEnumType(os
, map
, num_values
);
471 EnumVectorParam
<Map
>::showType(ostream
&os
) const
474 showEnumType(os
, map
, num_values
);
477 template EnumParam
<const char *>;
478 template EnumVectorParam
<const char *>;
480 template EnumParam
<EnumParamMap
>;
481 template EnumVectorParam
<EnumParamMap
>;
483 ////////////////////////////////////////////////////////////////////////
485 // SimObjectBaseParam methods
487 ////////////////////////////////////////////////////////////////////////
490 parseSimObjectParam(ParamContext
*context
, const string
&s
, SimObject
*&value
)
494 if (to_lower(s
) == "null") {
495 // explicitly set to null by user; assume that's OK
499 obj
= context
->resolveSimObject(s
);
511 SimObjectBaseParam::showValue(ostream
&os
, SimObject
*value
) const
513 os
<< (value
? value
->name() : "null");
517 SimObjectBaseParam::parse(const string
&s
, SimObject
*&value
)
519 if (parseSimObjectParam(context
, s
, value
)) {
523 string
err("could not resolve object name \"");
533 SimObjectBaseParam::parse(const string
&s
, vector
<SimObject
*>&value
)
535 vector
<string
> tokens
;
537 tokenize(tokens
, s
, ' ');
539 value
.resize(tokens
.size());
541 for (int i
= 0; i
< tokens
.size(); i
++) {
542 if (!parseSimObjectParam(context
, tokens
[i
], value
[i
])) {
543 string
err("could not resolve object name \"");
555 ////////////////////////////////////////////////////////////////////////
557 // ParamContext member definitions
559 ////////////////////////////////////////////////////////////////////////
561 list
<ParamContext
*> *ParamContext::ctxList
= NULL
;
563 ParamContext::ParamContext(const string
&_iniSection
, bool noAutoParse
)
564 : iniFilePtr(NULL
), // initialized on call to parseParams()
565 iniSection(_iniSection
), paramList(NULL
)
569 ctxList
= new list
<ParamContext
*>();
571 (*ctxList
).push_back(this);
577 ParamContext::addParam(BaseParam
*param
)
579 getParamList()->push_back(param
);
584 ParamContext::parseParams(IniFile
&iniFile
)
586 iniFilePtr
= &iniFile
; // set object member
588 ParamList::iterator i
;
590 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
593 if (iniFile
.findDefault(iniSection
, (*i
)->name
, string_value
)) {
594 (*i
)->parse(string_value
);
600 // Check parameter values for validity & consistency. Default
601 // implementation is no-op; derive subclass & override to add
602 // actual functionality here.
604 ParamContext::checkParams()
610 // Clean up context-related objects at end of execution. Default
611 // implementation is no-op; derive subclass & override to add actual
612 // functionality here.
614 ParamContext::cleanup()
621 ParamContext::describeParams(ostream
&os
)
623 ParamList::iterator i
;
625 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
628 os
<< p
->name
<< " (";
630 os
<< "): " << p
->description
<< "\n";
637 ParamContext::showParams(ostream
&os
)
639 ParamList::iterator i
;
641 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
645 os
<< p
->name
<< "=";
650 os
<< "// "<< p
->name
<< " not specified" << endl
;
657 ParamContext::printErrorProlog(ostream
&os
)
659 os
<< "Parameter error in section [" << iniSection
<< "]: " << endl
;
663 // Resolve an object name to a SimObject pointer. The object will be
664 // created as a side-effect if necessary. If the name contains a
665 // colon (e.g., "iq:IQ"), then the object is local (invisible to
666 // outside this context). If there is no colon, the name needs to be
667 // resolved through the configuration hierarchy (only possible for
668 // SimObjectBuilder objects, which return non-NULL for configNode()).
671 ParamContext::resolveSimObject(const string
&_name
)
674 string::size_type i
= _name
.find(':');
676 if (i
!= string::npos
) {
677 // colon found: local object
678 // add as child to current node and create it
679 name
= _name
.substr(0, i
);
680 string objConfigClassName
= _name
.substr(i
+ 1);
681 getConfigNode()->addChild(name
, objConfigClassName
);
683 ConfigNode
*n
= getConfigNode();
684 return n
? n
->resolveSimObject(name
) : NULL
;
689 // static method: call parseParams() on all registered contexts
692 ParamContext::parseAllContexts(IniFile
&iniFile
)
694 list
<ParamContext
*>::iterator iter
;
696 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
697 ParamContext
*pc
= *iter
;
699 pc
->parseParams(iniFile
);
705 // static method: call checkParams() on all registered contexts
708 ParamContext::checkAllContexts()
710 list
<ParamContext
*>::iterator iter
;
712 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
713 ParamContext
*pc
= *iter
;
721 // static method: call showParams() on all registered contexts
724 ParamContext::showAllContexts(ostream
&os
)
726 list
<ParamContext
*>::iterator iter
;
728 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
729 ParamContext
*pc
= *iter
;
731 os
<< "[" << pc
->iniSection
<< "]" << endl
;
739 // static method: call cleanup() on all registered contexts
742 ParamContext::cleanupAllContexts()
744 list
<ParamContext
*>::iterator iter
;
746 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
747 ParamContext
*pc
= *iter
;
755 // static method: call describeParams() on all registered contexts
758 ParamContext::describeAllContexts(ostream
&os
)
760 list
<ParamContext
*>::iterator iter
;
762 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
763 ParamContext
*pc
= *iter
;
765 os
<< "[" << pc
->iniSection
<< "]\n";
766 pc
->describeParams(os
);