2 * Copyright (c) 2002-2005 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.
35 #include "base/inifile.hh"
36 #include "base/misc.hh"
37 #include "base/range.hh"
38 #include "base/str.hh"
39 #include "base/trace.hh"
40 #include "sim/config_node.hh"
41 #include "sim/configfile.hh"
42 #include "sim/param.hh"
43 #include "sim/sim_object.hh"
48 ////////////////////////////////////////////////////////////////////////
50 // BaseParam member definitions
52 ////////////////////////////////////////////////////////////////////////
55 BaseParam::die(const string
&err
) const
57 context
->printErrorProlog(cerr
);
58 cerr
<< " parameter '" << name
<< "': "
64 ////////////////////////////////////////////////////////////////////////
66 // Param<T> and VectorParam<T> member definitions
68 // We implement parsing & displaying values for various parameter
69 // types T using a set of overloaded functions:
71 // - parseParam(string s, T &value) parses s into value
72 // - showParam(ostream &os, T &value) displays value on os
74 // By making these independent functions, we can reuse the same code
75 // for type T in both Param<T> and VectorParam<T>.
77 // For enum types, the parseParam function requires additional
78 // arguments, in which case we must specialize the Param<T>::parse and
79 // VectorParam<T>::parse calls as well.
81 // Type-specific instances come first, followed by more generic
82 // templated versions and their instantiations.
84 ////////////////////////////////////////////////////////////////////////
87 // The base implementations use to_number for parsing and '<<' for
88 // displaying, suitable for integer types.
92 parseParam(const string
&s
, T
&value
)
94 return to_number(s
, value
);
99 showParam(ostream
&os
, T
const &value
)
105 // Template specializations:
106 // - char (8-bit integer)
107 // - floating-point types
112 // Treat 8-bit ints (chars) as ints on output, not as chars
115 showParam(ostream
&os
, const char &value
)
123 showParam(ostream
&os
, const unsigned char &value
)
125 os
<< (unsigned int)value
;
129 // Use sscanf() for FP types as to_number() only handles integers
132 parseParam(const string
&s
, float &value
)
134 return (sscanf(s
.c_str(), "%f", &value
) == 1);
139 parseParam(const string
&s
, double &value
)
141 return (sscanf(s
.c_str(), "%lf", &value
) == 1);
144 // Be flexible about what we take for bool
147 parseParam(const string
&s
, bool &value
)
149 const string
&ls
= to_lower(s
);
151 if (ls
== "true" || ls
== "t" || ls
== "yes" || ls
== "y" || ls
== "1") {
156 if (ls
== "false" || ls
== "f" || ls
== "no" || ls
== "n" || ls
== "0") {
164 // Display bools as strings
167 showParam(ostream
&os
, const bool &value
)
169 os
<< (value
? "true" : "false");
173 // String requires no processing to speak of
176 parseParam(const string
&s
, string
&value
)
184 parseParam(const string
&s
, Range
<uint32_t> &value
)
187 return value
.valid();
192 parseParam(const string
&s
, Range
<uint64_t> &value
)
195 return value
.valid();
199 // End of parseParam/showParam definitions. Now we move on to
200 // incorporate them into the Param/VectorParam parse() and showValue()
204 // These definitions for Param<T>::parse and VectorParam<T>::parse
205 // work for any type for which parseParam() takes only two arguments
206 // (i.e., all the fundamental types like int, bool, etc.), thanks to
210 Param
<T
>::parse(const string
&s
)
212 if (parseParam(s
, value
)) {
216 string
err("could not parse \"");
227 VectorParam
<T
>::parse(const string
&s
)
234 vector
<string
> tokens
;
236 tokenize(tokens
, s
, ' ');
238 value
.resize(tokens
.size());
240 for (int i
= 0; i
< tokens
.size(); i
++) {
241 // need to parse into local variable to handle vector<bool>,
242 // for which operator[] returns a special reference class
243 // that's not the same as 'bool&', (since it's a packed
246 if (!parseParam(tokens
[i
], scalar_value
)) {
247 string
err("could not parse \"");
255 // assign parsed value to vector
256 value
[i
] = scalar_value
;
262 // These definitions for Param<T>::showValue() and
263 // VectorParam<T>::showValue() work for any type where showParam()
264 // takes only two arguments (i.e., everything but the SimpleEnum and
265 // MappedEnum classes).
268 Param
<T
>::showValue(ostream
&os
) const
270 showParam(os
, value
);
275 VectorParam
<T
>::showValue(ostream
&os
) const
277 for (int i
= 0; i
< value
.size(); i
++) {
281 showParam(os
, value
[i
]);
287 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
288 void Param<type>::showType(ostream &os) const { os << typestr; } \
289 void VectorParam<type>::showType(ostream &os) const { \
290 os << "vector of " << typestr; \
292 template Param<type>; \
293 template VectorParam<type>;
296 // instantiate all four methods (parse/show, scalar/vector) for basic
297 // types that can use the above templates
298 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
299 template bool parseParam<type>(const string &s, type &value); \
300 template void showParam<type>(ostream &os, type const &value); \
301 template void Param<type>::parse(const string &); \
302 template void VectorParam<type>::parse(const string &); \
303 template void Param<type>::showValue(ostream &) const; \
304 template void VectorParam<type>::showValue(ostream &) const; \
305 template <> void Param<type>::showType(ostream &os) const { os << typestr; } \
306 template <> void VectorParam<type>::showType(ostream &os) const { \
307 os << "vector of " << typestr; \
311 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
312 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
313 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
314 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
315 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
316 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
317 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
318 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
319 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
320 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
322 INSTANTIATE_PARAM_TEMPLATES(float, "float")
323 INSTANTIATE_PARAM_TEMPLATES(double, "double")
325 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
326 INSTANTIATE_PARAM_TEMPLATES(string
, "string")
328 INSTANTIATE_PARAM_TEMPLATES(Range
<uint64_t>, "uint64 range")
329 INSTANTIATE_PARAM_TEMPLATES(Range
<uint32_t>, "uint32 range")
331 #undef INSTANTIATE_PARAM_TEMPLATES
334 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
335 // showValue(), and showType() methods.
339 // SimpleEnumParam & SimpleEnumVectorParam
342 parseEnumParam(const char *const *map
, const int num_values
,
343 const string
&s
, int &value
)
345 for (int i
= 0; i
< num_values
; ++i
) {
356 showEnumParam(ostream
&os
,
357 const char *const *map
, const int num_values
,
360 assert(0 <= value
&& value
< num_values
);
365 showEnumType(ostream
&os
,
366 const char *const *map
, const int num_values
)
369 for (int i
= 1; i
< num_values
; ++i
)
377 // MappedEnumParam & MappedEnumVectorParam
380 parseEnumParam(const EnumParamMap
*map
, const int num_values
,
381 const string
&s
, int &value
)
383 for (int i
= 0; i
< num_values
; ++i
) {
384 if (s
== map
[i
].name
) {
385 value
= map
[i
].value
;
394 showEnumParam(ostream
&os
,
395 const EnumParamMap
*map
, const int num_values
,
398 for (int i
= 0; i
< num_values
; ++i
) {
399 if (value
== map
[i
].value
) {
405 // if we can't find a reverse mapping just print the int value
410 showEnumType(ostream
&os
,
411 const EnumParamMap
*map
, const int num_values
)
413 os
<< "{" << map
[0].name
;
414 for (int i
= 1; i
< num_values
; ++i
)
415 os
<< "," << map
[i
].name
;
423 EnumParam
<Map
>::parse(const string
&s
)
425 if (parseEnumParam(map
, num_values
, s
, value
)) {
428 string
err("no match for enum string \"");
439 EnumVectorParam
<Map
>::parse(const string
&s
)
441 vector
<string
> tokens
;
448 tokenize(tokens
, s
, ' ');
450 value
.resize(tokens
.size());
452 for (int i
= 0; i
< tokens
.size(); i
++) {
453 if (!parseEnumParam(map
, num_values
, tokens
[i
], value
[i
])) {
454 string
err("no match for enum string \"");
468 EnumParam
<Map
>::showValue(ostream
&os
) const
470 showEnumParam(os
, map
, num_values
, value
);
475 EnumVectorParam
<Map
>::showValue(ostream
&os
) const
477 for (int i
= 0; i
< value
.size(); i
++) {
481 showEnumParam(os
, map
, num_values
, value
[i
]);
487 EnumParam
<Map
>::showType(ostream
&os
) const
489 showEnumType(os
, map
, num_values
);
494 EnumVectorParam
<Map
>::showType(ostream
&os
) const
497 showEnumType(os
, map
, num_values
);
500 template class EnumParam
<const char *>;
501 template class EnumVectorParam
<const char *>;
503 template class EnumParam
<EnumParamMap
>;
504 template class EnumVectorParam
<EnumParamMap
>;
506 ////////////////////////////////////////////////////////////////////////
508 // SimObjectBaseParam methods
510 ////////////////////////////////////////////////////////////////////////
513 parseSimObjectParam(ParamContext
*context
, const string
&s
, SimObject
*&value
)
517 if (to_lower(s
) == "null") {
518 // explicitly set to null by user; assume that's OK
522 obj
= context
->resolveSimObject(s
);
534 SimObjectBaseParam::showValue(ostream
&os
, SimObject
*value
) const
536 os
<< (value
? value
->name() : "null");
540 SimObjectBaseParam::parse(const string
&s
, SimObject
*&value
)
542 if (parseSimObjectParam(context
, s
, value
)) {
546 string
err("could not resolve object name \"");
556 SimObjectBaseParam::parse(const string
&s
, vector
<SimObject
*>&value
)
558 vector
<string
> tokens
;
560 tokenize(tokens
, s
, ' ');
562 value
.resize(tokens
.size());
564 for (int i
= 0; i
< tokens
.size(); i
++) {
565 if (!parseSimObjectParam(context
, tokens
[i
], value
[i
])) {
566 string
err("could not resolve object name \"");
578 ////////////////////////////////////////////////////////////////////////
580 // ParamContext member definitions
582 ////////////////////////////////////////////////////////////////////////
584 list
<ParamContext
*> *ParamContext::ctxList
= NULL
;
586 ParamContext::ParamContext(const string
&_iniSection
, InitPhase _initPhase
)
587 : iniFilePtr(NULL
), // initialized on call to parseParams()
588 iniSection(_iniSection
), paramList(NULL
),
589 initPhase(_initPhase
)
591 // Put this context on global list for initialization
592 if (initPhase
!= NoAutoInit
) {
594 ctxList
= new list
<ParamContext
*>();
596 // keep list sorted by ascending initPhase values
597 list
<ParamContext
*>::iterator i
= ctxList
->begin();
598 list
<ParamContext
*>::iterator end
= ctxList
->end();
599 for (; i
!= end
; ++i
) {
600 if (initPhase
<= (*i
)->initPhase
) {
601 // found where we want to insert
605 // (fall through case: insert at end)
606 ctxList
->insert(i
, this);
612 ParamContext::addParam(BaseParam
*param
)
614 getParamList()->push_back(param
);
619 ParamContext::parseParams(IniFile
&iniFile
)
621 iniFilePtr
= &iniFile
; // set object member
623 ParamList::iterator i
;
625 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
628 if (iniFile
.find(iniSection
, (*i
)->name
, string_value
))
629 (*i
)->parse(string_value
);
634 // Check parameter values for validity & consistency. Default
635 // implementation is no-op; derive subclass & override to add
636 // actual functionality here.
638 ParamContext::checkParams()
644 // Clean up context-related objects at end of execution. Default
645 // implementation is no-op; derive subclass & override to add actual
646 // functionality here.
648 ParamContext::cleanup()
655 ParamContext::describeParams(ostream
&os
)
657 ParamList::iterator i
;
659 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
662 os
<< p
->name
<< " (";
664 os
<< "): " << p
->description
<< "\n";
671 ParamContext::showParams(ostream
&os
)
673 ParamList::iterator i
;
675 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
679 os
<< p
->name
<< "=";
684 os
<< "// "<< p
->name
<< " not specified" << endl
;
691 ParamContext::printErrorProlog(ostream
&os
)
693 os
<< "Parameter error in section [" << iniSection
<< "]: " << endl
;
697 // Resolve an object name to a SimObject pointer. The object will be
698 // created as a side-effect if necessary. If the name contains a
699 // colon (e.g., "iq:IQ"), then the object is local (invisible to
700 // outside this context). If there is no colon, the name needs to be
701 // resolved through the configuration hierarchy (only possible for
702 // SimObjectBuilder objects, which return non-NULL for configNode()).
705 ParamContext::resolveSimObject(const string
&name
)
707 ConfigNode
*n
= getConfigNode();
708 return n
? n
->resolveSimObject(name
) : NULL
;
713 // static method: call parseParams() on all registered contexts
716 ParamContext::parseAllContexts(IniFile
&iniFile
)
718 list
<ParamContext
*>::iterator iter
;
720 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
721 ParamContext
*pc
= *iter
;
723 pc
->parseParams(iniFile
);
729 // static method: call checkParams() on all registered contexts
732 ParamContext::checkAllContexts()
734 list
<ParamContext
*>::iterator iter
;
736 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
737 ParamContext
*pc
= *iter
;
745 // static method: call showParams() on all registered contexts
748 ParamContext::showAllContexts(ostream
&os
)
750 list
<ParamContext
*>::iterator iter
;
752 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
753 ParamContext
*pc
= *iter
;
755 os
<< "[" << pc
->iniSection
<< "]" << endl
;
763 // static method: call cleanup() on all registered contexts
766 ParamContext::cleanupAllContexts()
768 list
<ParamContext
*>::iterator iter
;
770 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
771 ParamContext
*pc
= *iter
;
779 // static method: call describeParams() on all registered contexts
782 ParamContext::describeAllContexts(ostream
&os
)
784 list
<ParamContext
*>::iterator iter
;
786 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
787 ParamContext
*pc
= *iter
;
789 os
<< "[" << pc
->iniSection
<< "]\n";
790 pc
->describeParams(os
);