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.
36 #include "base/inifile.hh"
37 #include "base/misc.hh"
38 #include "base/range.hh"
39 #include "base/str.hh"
40 #include "base/trace.hh"
41 #include "sim/config_node.hh"
42 #include "sim/configfile.hh"
43 #include "sim/param.hh"
44 #include "sim/sim_object.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
)
185 parseParam(const string
&s
, Range
<uint32_t> &value
)
188 return value
.valid();
193 parseParam(const string
&s
, Range
<uint64_t> &value
)
196 return value
.valid();
200 // End of parseParam/showParam definitions. Now we move on to
201 // incorporate them into the Param/VectorParam parse() and showValue()
205 // These definitions for Param<T>::parse and VectorParam<T>::parse
206 // work for any type for which parseParam() takes only two arguments
207 // (i.e., all the fundamental types like int, bool, etc.), thanks to
211 Param
<T
>::parse(const string
&s
)
213 if (parseParam(s
, value
)) {
217 string
err("could not parse \"");
228 VectorParam
<T
>::parse(const string
&s
)
235 vector
<string
> tokens
;
237 tokenize(tokens
, s
, ' ');
239 value
.resize(tokens
.size());
241 for (int i
= 0; i
< tokens
.size(); i
++) {
242 // need to parse into local variable to handle vector<bool>,
243 // for which operator[] returns a special reference class
244 // that's not the same as 'bool&', (since it's a packed
247 if (!parseParam(tokens
[i
], scalar_value
)) {
248 string
err("could not parse \"");
256 // assign parsed value to vector
257 value
[i
] = scalar_value
;
263 // These definitions for Param<T>::showValue() and
264 // VectorParam<T>::showValue() work for any type where showParam()
265 // takes only two arguments (i.e., everything but the SimpleEnum and
266 // MappedEnum classes).
269 Param
<T
>::showValue(ostream
&os
) const
271 showParam(os
, value
);
276 VectorParam
<T
>::showValue(ostream
&os
) const
278 for (int i
= 0; i
< value
.size(); i
++) {
282 showParam(os
, value
[i
]);
288 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
289 void Param<type>::showType(ostream &os) const { os << typestr; } \
290 void VectorParam<type>::showType(ostream &os) const { \
291 os << "vector of " << typestr; \
293 template Param<type>; \
294 template VectorParam<type>;
297 // instantiate all four methods (parse/show, scalar/vector) for basic
298 // types that can use the above templates
299 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
300 template bool parseParam<type>(const string &s, type &value); \
301 template void showParam<type>(ostream &os, type const &value); \
302 template void Param<type>::parse(const string &); \
303 template void VectorParam<type>::parse(const string &); \
304 template void Param<type>::showValue(ostream &) const; \
305 template void VectorParam<type>::showValue(ostream &) const; \
306 void Param<type>::showType(ostream &os) const { os << typestr; } \
307 void VectorParam<type>::showType(ostream &os) const { \
308 os << "vector of " << typestr; \
312 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
313 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
314 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
315 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
316 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
317 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
318 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
319 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
320 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
321 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
323 INSTANTIATE_PARAM_TEMPLATES(float, "float")
324 INSTANTIATE_PARAM_TEMPLATES(double, "double")
326 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
327 INSTANTIATE_PARAM_TEMPLATES(string
, "string")
329 INSTANTIATE_PARAM_TEMPLATES(Range
<uint64_t>, "uint64 range")
330 INSTANTIATE_PARAM_TEMPLATES(Range
<uint32_t>, "uint32 range")
332 #undef INSTANTIATE_PARAM_TEMPLATES
335 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
336 // showValue(), and showType() methods.
340 // SimpleEnumParam & SimpleEnumVectorParam
343 parseEnumParam(const char *const *map
, const int num_values
,
344 const string
&s
, int &value
)
346 for (int i
= 0; i
< num_values
; ++i
) {
357 showEnumParam(ostream
&os
,
358 const char *const *map
, const int num_values
,
361 assert(0 <= value
&& value
< num_values
);
366 showEnumType(ostream
&os
,
367 const char *const *map
, const int num_values
)
370 for (int i
= 1; i
< num_values
; ++i
)
378 // MappedEnumParam & MappedEnumVectorParam
381 parseEnumParam(const EnumParamMap
*map
, const int num_values
,
382 const string
&s
, int &value
)
384 for (int i
= 0; i
< num_values
; ++i
) {
385 if (s
== map
[i
].name
) {
386 value
= map
[i
].value
;
395 showEnumParam(ostream
&os
,
396 const EnumParamMap
*map
, const int num_values
,
399 for (int i
= 0; i
< num_values
; ++i
) {
400 if (value
== map
[i
].value
) {
406 // if we can't find a reverse mapping just print the int value
411 showEnumType(ostream
&os
,
412 const EnumParamMap
*map
, const int num_values
)
414 os
<< "{" << map
[0].name
;
415 for (int i
= 1; i
< num_values
; ++i
)
416 os
<< "," << map
[i
].name
;
424 EnumParam
<Map
>::parse(const string
&s
)
426 if (parseEnumParam(map
, num_values
, s
, value
)) {
429 string
err("no match for enum string \"");
440 EnumVectorParam
<Map
>::parse(const string
&s
)
442 vector
<string
> tokens
;
449 tokenize(tokens
, s
, ' ');
451 value
.resize(tokens
.size());
453 for (int i
= 0; i
< tokens
.size(); i
++) {
454 if (!parseEnumParam(map
, num_values
, tokens
[i
], value
[i
])) {
455 string
err("no match for enum string \"");
469 EnumParam
<Map
>::showValue(ostream
&os
) const
471 showEnumParam(os
, map
, num_values
, value
);
476 EnumVectorParam
<Map
>::showValue(ostream
&os
) const
478 for (int i
= 0; i
< value
.size(); i
++) {
482 showEnumParam(os
, map
, num_values
, value
[i
]);
488 EnumParam
<Map
>::showType(ostream
&os
) const
490 showEnumType(os
, map
, num_values
);
495 EnumVectorParam
<Map
>::showType(ostream
&os
) const
498 showEnumType(os
, map
, num_values
);
501 template class EnumParam
<const char *>;
502 template class EnumVectorParam
<const char *>;
504 template class EnumParam
<EnumParamMap
>;
505 template class EnumVectorParam
<EnumParamMap
>;
507 ////////////////////////////////////////////////////////////////////////
509 // SimObjectBaseParam methods
511 ////////////////////////////////////////////////////////////////////////
514 parseSimObjectParam(ParamContext
*context
, const string
&s
, SimObject
*&value
)
518 if (to_lower(s
) == "null") {
519 // explicitly set to null by user; assume that's OK
523 obj
= context
->resolveSimObject(s
);
535 SimObjectBaseParam::showValue(ostream
&os
, SimObject
*value
) const
537 os
<< (value
? value
->name() : "null");
541 SimObjectBaseParam::parse(const string
&s
, SimObject
*&value
)
543 if (parseSimObjectParam(context
, s
, value
)) {
547 string
err("could not resolve object name \"");
557 SimObjectBaseParam::parse(const string
&s
, vector
<SimObject
*>&value
)
559 vector
<string
> tokens
;
561 tokenize(tokens
, s
, ' ');
563 value
.resize(tokens
.size());
565 for (int i
= 0; i
< tokens
.size(); i
++) {
566 if (!parseSimObjectParam(context
, tokens
[i
], value
[i
])) {
567 string
err("could not resolve object name \"");
579 ////////////////////////////////////////////////////////////////////////
581 // ParamContext member definitions
583 ////////////////////////////////////////////////////////////////////////
585 list
<ParamContext
*> *ParamContext::ctxList
= NULL
;
587 ParamContext::ParamContext(const string
&_iniSection
, InitPhase _initPhase
)
588 : iniFilePtr(NULL
), // initialized on call to parseParams()
589 iniSection(_iniSection
), paramList(NULL
),
590 initPhase(_initPhase
)
592 // Put this context on global list for initialization
593 if (initPhase
!= NoAutoInit
) {
595 ctxList
= new list
<ParamContext
*>();
597 // keep list sorted by ascending initPhase values
598 list
<ParamContext
*>::iterator i
= ctxList
->begin();
599 list
<ParamContext
*>::iterator end
= ctxList
->end();
600 for (; i
!= end
; ++i
) {
601 if (initPhase
<= (*i
)->initPhase
) {
602 // found where we want to insert
606 // (fall through case: insert at end)
607 ctxList
->insert(i
, this);
613 ParamContext::addParam(BaseParam
*param
)
615 getParamList()->push_back(param
);
620 ParamContext::parseParams(IniFile
&iniFile
)
622 iniFilePtr
= &iniFile
; // set object member
624 ParamList::iterator i
;
626 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
629 if (iniFile
.find(iniSection
, (*i
)->name
, string_value
))
630 (*i
)->parse(string_value
);
635 // Check parameter values for validity & consistency. Default
636 // implementation is no-op; derive subclass & override to add
637 // actual functionality here.
639 ParamContext::checkParams()
645 // Clean up context-related objects at end of execution. Default
646 // implementation is no-op; derive subclass & override to add actual
647 // functionality here.
649 ParamContext::cleanup()
656 ParamContext::describeParams(ostream
&os
)
658 ParamList::iterator i
;
660 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
663 os
<< p
->name
<< " (";
665 os
<< "): " << p
->description
<< "\n";
672 ParamContext::showParams(ostream
&os
)
674 ParamList::iterator i
;
676 for (i
= getParamList()->begin(); i
!= getParamList()->end(); ++i
) {
680 os
<< p
->name
<< "=";
685 os
<< "// "<< p
->name
<< " not specified" << endl
;
692 ParamContext::printErrorProlog(ostream
&os
)
694 os
<< "Parameter error in section [" << iniSection
<< "]: " << endl
;
698 // Resolve an object name to a SimObject pointer. The object will be
699 // created as a side-effect if necessary. If the name contains a
700 // colon (e.g., "iq:IQ"), then the object is local (invisible to
701 // outside this context). If there is no colon, the name needs to be
702 // resolved through the configuration hierarchy (only possible for
703 // SimObjectBuilder objects, which return non-NULL for configNode()).
706 ParamContext::resolveSimObject(const string
&name
)
708 ConfigNode
*n
= getConfigNode();
709 return n
? n
->resolveSimObject(name
) : NULL
;
714 // static method: call parseParams() on all registered contexts
717 ParamContext::parseAllContexts(IniFile
&iniFile
)
719 list
<ParamContext
*>::iterator iter
;
721 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
722 ParamContext
*pc
= *iter
;
724 pc
->parseParams(iniFile
);
730 // static method: call checkParams() on all registered contexts
733 ParamContext::checkAllContexts()
735 list
<ParamContext
*>::iterator iter
;
737 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
738 ParamContext
*pc
= *iter
;
746 // static method: call showParams() on all registered contexts
749 ParamContext::showAllContexts(ostream
&os
)
751 list
<ParamContext
*>::iterator iter
;
753 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
754 ParamContext
*pc
= *iter
;
756 os
<< "[" << pc
->iniSection
<< "]" << endl
;
764 // static method: call cleanup() on all registered contexts
767 ParamContext::cleanupAllContexts()
769 list
<ParamContext
*>::iterator iter
;
771 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
772 ParamContext
*pc
= *iter
;
780 // static method: call describeParams() on all registered contexts
783 ParamContext::describeAllContexts(ostream
&os
)
785 list
<ParamContext
*>::iterator iter
;
787 for (iter
= ctxList
->begin(); iter
!= ctxList
->end(); ++iter
) {
788 ParamContext
*pc
= *iter
;
790 os
<< "[" << pc
->iniSection
<< "]\n";
791 pc
->describeParams(os
);