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 // Integer types all use to_number for parsing and '<<' for
91 #define INT_PARAM(type) \
93 parseParam(const string &s, type &value) \
95 return to_number(s, value); \
99 showParam(ostream &os, type value) \
104 INT_PARAM(unsigned long long)
105 INT_PARAM(signed long long)
106 INT_PARAM(unsigned long)
107 INT_PARAM(signed long)
108 INT_PARAM(unsigned int)
109 INT_PARAM(signed int)
110 INT_PARAM(unsigned short)
111 INT_PARAM(signed short)
112 INT_PARAM(unsigned char)
113 INT_PARAM(signed char)
118 // Floating-point types
121 parseParam(const string
&s
, float &value
)
123 return (sscanf(s
.c_str(), "%f", &value
) == 1);
127 parseParam(const string
&s
, double &value
)
129 return (sscanf(s
.c_str(), "%lf", &value
) == 1);
132 void showParam(ostream
&os
, float value
) { os
<< value
; }
133 void showParam(ostream
&os
, double value
) { os
<< value
; }
139 parseParam(const string
&s
, bool &value
)
141 const string
&lower
= to_lower(s
);
143 if (lower
== "true" || lower
== "t" || lower
== "yes" || lower
== "y") {
148 if (lower
== "false" || lower
== "f" || lower
== "no" || lower
== "n") {
158 showParam(ostream
&os
, bool value
)
160 os
<< (value
? "true" : "false");
168 parseParam(const string
&s
, string
&value
)
176 showParam(ostream
&os
, const string
&value
)
182 // End of parseParam/showParam definitions. Now we move on to
183 // incorporate them into the Param/VectorParam parse() and showValue()
187 // These definitions for Param<T>::parse and VectorParam<T>::parse
188 // work for any type for which parseParam() takes only two arguments
189 // (i.e., all the fundamental types like int, bool, etc.), thanks to
193 Param
<T
>::parse(const string
&s
)
195 if (parseParam(s
, value
)) {
199 string
err("could not parse \"");
210 VectorParam
<T
>::parse(const string
&s
)
212 vector
<string
> tokens
;
214 tokenize(tokens
, s
, ' ');
216 value
.resize(tokens
.size());
218 for (int i
= 0; i
< tokens
.size(); i
++) {
219 // need to parse into local variable to handle vector<bool>,
220 // for which operator[] returns a special reference class
221 // that's not the same as 'bool&', (since it's a packed
224 if (!parseParam(tokens
[i
], scalar_value
)) {
225 string
err("could not parse \"");
233 // assign parsed value to vector
234 value
[i
] = scalar_value
;
240 // These definitions for Param<T>::showValue() and
241 // VectorParam<T>::showValue() work for any type where showParam()
242 // takes only two arguments (i.e., everything but the SimpleEnum and
243 // MappedEnum classes).
246 Param
<T
>::showValue(ostream
&os
) const
248 showParam(os
, value
);
253 VectorParam
<T
>::showValue(ostream
&os
) const
255 for (int i
= 0; i
< value
.size(); i
++) {
259 showParam(os
, value
[i
]);
265 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
266 void Param<type>::showType(ostream &os) const { os << typestr; } \
267 void VectorParam<type>::showType(ostream &os) const { \
268 os << "vector of " << typestr; \
270 template Param<type>; \
271 template VectorParam<type>;
274 // instantiate all four methods (parse/show, scalar/vector) for basic
275 // types that can use the above templates
276 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
277 template void Param<type>::parse(const string &); \
278 template void VectorParam<type>::parse(const string &); \
279 template void Param<type>::showValue(ostream &) const; \
280 template void VectorParam<type>::showValue(ostream &) const; \
281 void Param<type>::showType(ostream &os) const { os << typestr; } \
282 void VectorParam<type>::showType(ostream &os) const { \
283 os << "vector of " << typestr; \
287 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
288 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
289 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
290 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
291 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
292 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
293 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
294 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
295 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
296 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
298 INSTANTIATE_PARAM_TEMPLATES(float, "float")
299 INSTANTIATE_PARAM_TEMPLATES(double, "double")
301 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
302 INSTANTIATE_PARAM_TEMPLATES(string
, "string")
304 #undef INSTANTIATE_PARAM_TEMPLATES
307 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
308 // showValue(), and showType() methods.
312 // SimpleEnumParam & SimpleEnumVectorParam
315 parseEnumParam(const char *const *map
, const int num_values
,
316 const string
&s
, int &value
)
318 for (int i
= 0; i
< num_values
; ++i
) {
329 showEnumParam(ostream
&os
,
330 const char *const *map
, const int num_values
,
333 assert(0 <= value
&& value
< num_values
);
338 showEnumType(ostream
&os
,
339 const char *const *map
, const int num_values
)
342 for (int i
= 1; i
< num_values
; ++i
)
350 // MappedEnumParam & MappedEnumVectorParam
353 parseEnumParam(const EnumParamMap
*map
, const int num_values
,
354 const string
&s
, int &value
)
356 for (int i
= 0; i
< num_values
; ++i
) {
357 if (s
== map
[i
].name
) {
358 value
= map
[i
].value
;
367 showEnumParam(ostream
&os
,
368 const EnumParamMap
*map
, const int num_values
,
371 for (int i
= 0; i
< num_values
; ++i
) {
372 if (value
== map
[i
].value
) {
378 // if we can't find a reverse mapping just print the int value
383 showEnumType(ostream
&os
,
384 const EnumParamMap
*map
, const int num_values
)
386 os
<< "{" << map
[0].name
;
387 for (int i
= 1; i
< num_values
; ++i
)
388 os
<< "," << map
[i
].name
;
396 EnumParam
<Map
>::parse(const string
&s
)
398 if (parseEnumParam(map
, num_values
, s
, value
)) {
401 string
err("no match for enum string \"");
412 EnumVectorParam
<Map
>::parse(const string
&s
)
414 vector
<string
> tokens
;
416 tokenize(tokens
, s
, ' ');
418 value
.resize(tokens
.size());
420 for (int i
= 0; i
< tokens
.size(); i
++) {
421 if (!parseEnumParam(map
, num_values
, tokens
[i
], value
[i
])) {
422 string
err("no match for enum string \"");
436 EnumParam
<Map
>::showValue(ostream
&os
) const
438 showEnumParam(os
, map
, num_values
, value
);
443 EnumVectorParam
<Map
>::showValue(ostream
&os
) const
445 for (int i
= 0; i
< value
.size(); i
++) {
449 showEnumParam(os
, map
, num_values
, value
[i
]);
455 EnumParam
<Map
>::showType(ostream
&os
) const
457 showEnumType(os
, map
, num_values
);
462 EnumVectorParam
<Map
>::showType(ostream
&os
) const
465 showEnumType(os
, map
, num_values
);
468 template EnumParam
<const char *>;
469 template EnumVectorParam
<const char *>;
471 template EnumParam
<EnumParamMap
>;
472 template EnumVectorParam
<EnumParamMap
>;
474 ////////////////////////////////////////////////////////////////////////
476 // SimObjectBaseParam methods
478 ////////////////////////////////////////////////////////////////////////
481 parseSimObjectParam(ParamContext
*context
, const string
&s
, SimObject
*&value
)
485 if (to_lower(s
) == "null") {
486 // explicitly set to null by user; assume that's OK
490 obj
= context
->resolveSimObject(s
);
502 SimObjectBaseParam::showValue(ostream
&os
, SimObject
*value
) const
504 os
<< (value
? value
->name() : "null");
508 SimObjectBaseParam::parse(const string
&s
, SimObject
*&value
)
510 if (parseSimObjectParam(context
, s
, value
)) {
514 string
err("could not resolve object name \"");
524 SimObjectBaseParam::parse(const string
&s
, vector
<SimObject
*>&value
)
526 vector
<string
> tokens
;
528 tokenize(tokens
, s
, ' ');
530 value
.resize(tokens
.size());
532 for (int i
= 0; i
< tokens
.size(); i
++) {
533 if (!parseSimObjectParam(context
, tokens
[i
], value
[i
])) {
534 string
err("could not resolve object name \"");
546 ////////////////////////////////////////////////////////////////////////
548 // ParamContext member definitions
550 ////////////////////////////////////////////////////////////////////////
552 list
<ParamContext
*> *ParamContext::ctxList
= NULL
;
554 ParamContext::ParamContext(const string
&_iniSection
, bool noAutoParse
)
555 : iniFilePtr(NULL
), // initialized on call to parseParams()
556 iniSection(_iniSection
), paramList(NULL
)
560 ctxList
= new list
<ParamContext
*>();
562 (*ctxList
).push_back(this);
568 ParamContext::addParam(BaseParam
*param
)
570 getParamList()->push_back(param
);
575 ParamContext::parseParams(IniFile
&iniFile
)
577 iniFilePtr
= &iniFile
; // set object member
579 ParamList::iterator i
;
581 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
584 if (iniFile
.findDefault(iniSection
, (*i
)->name
, string_value
)) {
585 (*i
)->parse(string_value
);
591 // Check parameter values for validity & consistency. Default
592 // implementation is no-op; derive subclass & override to add
593 // actual functionality here.
595 ParamContext::checkParams()
601 // Clean up context-related objects at end of execution. Default
602 // implementation is no-op; derive subclass & override to add actual
603 // functionality here.
605 ParamContext::cleanup()
612 ParamContext::describeParams(ostream
&os
)
614 ParamList::iterator i
;
616 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
619 os
<< p
->name
<< " (";
621 os
<< "): " << p
->description
<< "\n";
628 ParamContext::showParams(ostream
&os
)
630 ParamList::iterator i
;
632 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
636 os
<< p
->name
<< "=";
641 os
<< "// "<< p
->name
<< " not specified" << endl
;
648 ParamContext::printErrorProlog(ostream
&os
)
650 os
<< "Parameter error in section [" << iniSection
<< "]: " << endl
;
654 // Resolve an object name to a SimObject pointer. The object will be
655 // created as a side-effect if necessary. If the name contains a
656 // colon (e.g., "iq:IQ"), then the object is local (invisible to
657 // outside this context). If there is no colon, the name needs to be
658 // resolved through the configuration hierarchy (only possible for
659 // SimObjectBuilder objects, which return non-NULL for configNode()).
662 ParamContext::resolveSimObject(const string
&_name
)
665 string::size_type i
= _name
.find(':');
667 if (i
!= string::npos
) {
668 // colon found: local object
669 // add as child to current node and create it
670 name
= _name
.substr(0, i
);
671 string objConfigClassName
= _name
.substr(i
+ 1);
672 getConfigNode()->addChild(name
, objConfigClassName
);
674 ConfigNode
*n
= getConfigNode();
675 return n
? n
->resolveSimObject(name
) : NULL
;
680 // static method: call parseParams() on all registered contexts
683 ParamContext::parseAllContexts(IniFile
&iniFile
)
685 list
<ParamContext
*>::iterator iter
;
687 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
688 ParamContext
*pc
= *iter
;
690 pc
->parseParams(iniFile
);
696 // static method: call checkParams() on all registered contexts
699 ParamContext::checkAllContexts()
701 list
<ParamContext
*>::iterator iter
;
703 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
704 ParamContext
*pc
= *iter
;
712 // static method: call showParams() on all registered contexts
715 ParamContext::showAllContexts(ostream
&os
)
717 list
<ParamContext
*>::iterator iter
;
719 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
720 ParamContext
*pc
= *iter
;
722 os
<< "[" << pc
->iniSection
<< "]" << endl
;
730 // static method: call cleanup() on all registered contexts
733 ParamContext::cleanupAllContexts()
735 list
<ParamContext
*>::iterator iter
;
737 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
738 ParamContext
*pc
= *iter
;
746 // static method: call describeParams() on all registered contexts
749 ParamContext::describeAllContexts(ostream
&os
)
751 list
<ParamContext
*>::iterator iter
;
753 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
754 ParamContext
*pc
= *iter
;
756 os
<< "[" << pc
->iniSection
<< "]\n";
757 pc
->describeParams(os
);