First steps toward getting full system to work with
[gem5.git] / sim / param.cc
1 /*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
29 #include <algorithm>
30 #include <cassert>
31 #include <list>
32 #include <string>
33 #include <vector>
34
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"
44
45 using namespace std;
46
47
48 ////////////////////////////////////////////////////////////////////////
49 //
50 // BaseParam member definitions
51 //
52 ////////////////////////////////////////////////////////////////////////
53
54 void
55 BaseParam::die(const string &err) const
56 {
57 context->printErrorProlog(cerr);
58 cerr << " parameter '" << name << "': "
59 << err << endl;
60 abort();
61 }
62
63
64 ////////////////////////////////////////////////////////////////////////
65 //
66 // Param<T> and VectorParam<T> member definitions
67 //
68 // We implement parsing & displaying values for various parameter
69 // types T using a set of overloaded functions:
70 //
71 // - parseParam(string s, T &value) parses s into value
72 // - showParam(ostream &os, T &value) displays value on os
73 //
74 // By making these independent functions, we can reuse the same code
75 // for type T in both Param<T> and VectorParam<T>.
76 //
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.
80 //
81 // Type-specific instances come first, followed by more generic
82 // templated versions and their instantiations.
83 //
84 ////////////////////////////////////////////////////////////////////////
85
86 //
87 // The base implementations use to_number for parsing and '<<' for
88 // displaying, suitable for integer types.
89 //
90 template <class T>
91 bool
92 parseParam(const string &s, T &value)
93 {
94 return to_number(s, value);
95 }
96
97 template <class T>
98 void
99 showParam(ostream &os, T const &value)
100 {
101 os << value;
102 }
103
104 //
105 // Template specializations:
106 // - char (8-bit integer)
107 // - floating-point types
108 // - bool
109 // - string
110 //
111
112 // Treat 8-bit ints (chars) as ints on output, not as chars
113 template <>
114 void
115 showParam(ostream &os, const char &value)
116 {
117 os << (int)value;
118 }
119
120
121 template <>
122 void
123 showParam(ostream &os, const unsigned char &value)
124 {
125 os << (unsigned int)value;
126 }
127
128
129 // Use sscanf() for FP types as to_number() only handles integers
130 template <>
131 bool
132 parseParam(const string &s, float &value)
133 {
134 return (sscanf(s.c_str(), "%f", &value) == 1);
135 }
136
137 template <>
138 bool
139 parseParam(const string &s, double &value)
140 {
141 return (sscanf(s.c_str(), "%lf", &value) == 1);
142 }
143
144 // Be flexible about what we take for bool
145 template <>
146 bool
147 parseParam(const string &s, bool &value)
148 {
149 const string &ls = to_lower(s);
150
151 if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") {
152 value = true;
153 return true;
154 }
155
156 if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") {
157 value = false;
158 return true;
159 }
160
161 return false;
162 }
163
164 // Display bools as strings
165 template <>
166 void
167 showParam(ostream &os, const bool &value)
168 {
169 os << (value ? "true" : "false");
170 }
171
172
173 // String requires no processing to speak of
174 template <>
175 bool
176 parseParam(const string &s, string &value)
177 {
178 value = s;
179 return true;
180 }
181
182 template <>
183 bool
184 parseParam(const string &s, Range<uint32_t> &value)
185 {
186 value = s;
187 return value.valid();
188 }
189
190 template <>
191 bool
192 parseParam(const string &s, Range<uint64_t> &value)
193 {
194 value = s;
195 return value.valid();
196 }
197
198 //
199 // End of parseParam/showParam definitions. Now we move on to
200 // incorporate them into the Param/VectorParam parse() and showValue()
201 // methods.
202 //
203
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
207 // overloading.
208 template <class T>
209 void
210 Param<T>::parse(const string &s)
211 {
212 if (parseParam(s, value)) {
213 wasSet = true;
214 }
215 else {
216 string err("could not parse \"");
217
218 err += s;
219 err += "\"";
220
221 die(err);
222 }
223 }
224
225 template <class T>
226 void
227 VectorParam<T>::parse(const string &s)
228 {
229 if (s.empty()) {
230 wasSet = true;
231 return;
232 }
233
234 vector<string> tokens;
235
236 tokenize(tokens, s, ' ');
237
238 value.resize(tokens.size());
239
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
244 // vector)
245 T scalar_value;
246 if (!parseParam(tokens[i], scalar_value)) {
247 string err("could not parse \"");
248
249 err += s;
250 err += "\"";
251
252 die(err);
253 }
254
255 // assign parsed value to vector
256 value[i] = scalar_value;
257 }
258
259 wasSet = true;
260 }
261
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).
266 template <class T>
267 void
268 Param<T>::showValue(ostream &os) const
269 {
270 showParam(os, value);
271 }
272
273 template <class T>
274 void
275 VectorParam<T>::showValue(ostream &os) const
276 {
277 for (int i = 0; i < value.size(); i++) {
278 if (i != 0) {
279 os << " ";
280 }
281 showParam(os, value[i]);
282 }
283 }
284
285
286 #ifdef INSURE_BUILD
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; \
291 } \
292 template Param<type>; \
293 template VectorParam<type>;
294
295 #else
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; \
308 }
309 #endif
310
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")
321
322 INSTANTIATE_PARAM_TEMPLATES(float, "float")
323 INSTANTIATE_PARAM_TEMPLATES(double, "double")
324
325 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
326 INSTANTIATE_PARAM_TEMPLATES(string, "string")
327
328 INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range")
329 INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range")
330
331 #undef INSTANTIATE_PARAM_TEMPLATES
332
333 //
334 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
335 // showValue(), and showType() methods.
336 //
337
338 //
339 // SimpleEnumParam & SimpleEnumVectorParam
340 //
341 bool
342 parseEnumParam(const char *const *map, const int num_values,
343 const string &s, int &value)
344 {
345 for (int i = 0; i < num_values; ++i) {
346 if (s == map[i]) {
347 value = i;
348 return true;
349 }
350 }
351
352 return false;
353 }
354
355 void
356 showEnumParam(ostream &os,
357 const char *const *map, const int num_values,
358 int value)
359 {
360 assert(0 <= value && value < num_values);
361 os << map[value];
362 }
363
364 void
365 showEnumType(ostream &os,
366 const char *const *map, const int num_values)
367 {
368 os << "{" << map[0];
369 for (int i = 1; i < num_values; ++i)
370 os << "," << map[i];
371
372 os << "}";
373 }
374
375
376 //
377 // MappedEnumParam & MappedEnumVectorParam
378 //
379 bool
380 parseEnumParam(const EnumParamMap *map, const int num_values,
381 const string &s, int &value)
382 {
383 for (int i = 0; i < num_values; ++i) {
384 if (s == map[i].name) {
385 value = map[i].value;
386 return true;
387 }
388 }
389
390 return false;
391 }
392
393 void
394 showEnumParam(ostream &os,
395 const EnumParamMap *map, const int num_values,
396 int value)
397 {
398 for (int i = 0; i < num_values; ++i) {
399 if (value == map[i].value) {
400 os << map[i].name;
401 return;
402 }
403 }
404
405 // if we can't find a reverse mapping just print the int value
406 os << value;
407 }
408
409 void
410 showEnumType(ostream &os,
411 const EnumParamMap *map, const int num_values)
412 {
413 os << "{" << map[0].name;
414 for (int i = 1; i < num_values; ++i)
415 os << "," << map[i].name;
416
417 os << "}";
418 }
419
420
421 template <class Map>
422 void
423 EnumParam<Map>::parse(const string &s)
424 {
425 if (parseEnumParam(map, num_values, s, value)) {
426 wasSet = true;
427 } else {
428 string err("no match for enum string \"");
429
430 err += s;
431 err += "\"";
432
433 die(err);
434 }
435 }
436
437 template <class Map>
438 void
439 EnumVectorParam<Map>::parse(const string &s)
440 {
441 vector<string> tokens;
442
443 if (s.empty()) {
444 wasSet = true;
445 return;
446 }
447
448 tokenize(tokens, s, ' ');
449
450 value.resize(tokens.size());
451
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 \"");
455
456 err += s;
457 err += "\"";
458
459 die(err);
460 }
461 }
462
463 wasSet = true;
464 }
465
466 template <class Map>
467 void
468 EnumParam<Map>::showValue(ostream &os) const
469 {
470 showEnumParam(os, map, num_values, value);
471 }
472
473 template <class Map>
474 void
475 EnumVectorParam<Map>::showValue(ostream &os) const
476 {
477 for (int i = 0; i < value.size(); i++) {
478 if (i != 0) {
479 os << " ";
480 }
481 showEnumParam(os, map, num_values, value[i]);
482 }
483 }
484
485 template <class Map>
486 void
487 EnumParam<Map>::showType(ostream &os) const
488 {
489 showEnumType(os, map, num_values);
490 }
491
492 template <class Map>
493 void
494 EnumVectorParam<Map>::showType(ostream &os) const
495 {
496 os << "vector of";
497 showEnumType(os, map, num_values);
498 }
499
500 template class EnumParam<const char *>;
501 template class EnumVectorParam<const char *>;
502
503 template class EnumParam<EnumParamMap>;
504 template class EnumVectorParam<EnumParamMap>;
505
506 ////////////////////////////////////////////////////////////////////////
507 //
508 // SimObjectBaseParam methods
509 //
510 ////////////////////////////////////////////////////////////////////////
511
512 bool
513 parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
514 {
515 SimObject *obj;
516
517 if (to_lower(s) == "null") {
518 // explicitly set to null by user; assume that's OK
519 obj = NULL;
520 }
521 else {
522 obj = context->resolveSimObject(s);
523
524 if (obj == NULL)
525 return false;
526 }
527
528 value = obj;
529 return true;
530 }
531
532
533 void
534 SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
535 {
536 os << (value ? value->name() : "null");
537 }
538
539 void
540 SimObjectBaseParam::parse(const string &s, SimObject *&value)
541 {
542 if (parseSimObjectParam(context, s, value)) {
543 wasSet = true;
544 }
545 else {
546 string err("could not resolve object name \"");
547
548 err += s;
549 err += "\"";
550
551 die(err);
552 }
553 }
554
555 void
556 SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
557 {
558 vector<string> tokens;
559
560 tokenize(tokens, s, ' ');
561
562 value.resize(tokens.size());
563
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 \"");
567
568 err += s;
569 err += "\"";
570
571 die(err);
572 }
573 }
574
575 wasSet = true;
576 }
577
578 ////////////////////////////////////////////////////////////////////////
579 //
580 // ParamContext member definitions
581 //
582 ////////////////////////////////////////////////////////////////////////
583
584 list<ParamContext *> *ParamContext::ctxList = NULL;
585
586 ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase)
587 : iniFilePtr(NULL), // initialized on call to parseParams()
588 iniSection(_iniSection), paramList(NULL),
589 initPhase(_initPhase)
590 {
591 // Put this context on global list for initialization
592 if (initPhase != NoAutoInit) {
593 if (ctxList == NULL)
594 ctxList = new list<ParamContext *>();
595
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
602 break;
603 }
604 }
605 // (fall through case: insert at end)
606 ctxList->insert(i, this);
607 }
608 }
609
610
611 void
612 ParamContext::addParam(BaseParam *param)
613 {
614 getParamList()->push_back(param);
615 }
616
617
618 void
619 ParamContext::parseParams(IniFile &iniFile)
620 {
621 iniFilePtr = &iniFile; // set object member
622
623 ParamList::iterator i;
624
625 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
626 string string_value;
627
628 if (iniFile.find(iniSection, (*i)->name, string_value))
629 (*i)->parse(string_value);
630 }
631 }
632
633
634 // Check parameter values for validity & consistency. Default
635 // implementation is no-op; derive subclass & override to add
636 // actual functionality here.
637 void
638 ParamContext::checkParams()
639 {
640 // nada
641 }
642
643
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.
647 void
648 ParamContext::cleanup()
649 {
650 // nada
651 }
652
653
654 void
655 ParamContext::describeParams(ostream &os)
656 {
657 ParamList::iterator i;
658
659 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
660 BaseParam *p = *i;
661
662 os << p->name << " (";
663 p->showType(os);
664 os << "): " << p->description << "\n";
665 }
666 }
667
668
669
670 void
671 ParamContext::showParams(ostream &os)
672 {
673 ParamList::iterator i;
674
675 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
676 BaseParam *p = *i;
677
678 if (p->isValid()) {
679 os << p->name << "=";
680 p->showValue(os);
681 os << endl;
682 }
683 else {
684 os << "// "<< p->name << " not specified" << endl;
685 }
686 }
687 }
688
689
690 void
691 ParamContext::printErrorProlog(ostream &os)
692 {
693 os << "Parameter error in section [" << iniSection << "]: " << endl;
694 }
695
696 //
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()).
703 //
704 SimObject *
705 ParamContext::resolveSimObject(const string &name)
706 {
707 ConfigNode *n = getConfigNode();
708 return n ? n->resolveSimObject(name) : NULL;
709 }
710
711
712 //
713 // static method: call parseParams() on all registered contexts
714 //
715 void
716 ParamContext::parseAllContexts(IniFile &iniFile)
717 {
718 list<ParamContext *>::iterator iter;
719
720 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
721 ParamContext *pc = *iter;
722
723 pc->parseParams(iniFile);
724 }
725 }
726
727
728 //
729 // static method: call checkParams() on all registered contexts
730 //
731 void
732 ParamContext::checkAllContexts()
733 {
734 list<ParamContext *>::iterator iter;
735
736 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
737 ParamContext *pc = *iter;
738
739 pc->checkParams();
740 }
741 }
742
743
744 //
745 // static method: call showParams() on all registered contexts
746 //
747 void
748 ParamContext::showAllContexts(ostream &os)
749 {
750 list<ParamContext *>::iterator iter;
751
752 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
753 ParamContext *pc = *iter;
754
755 os << "[" << pc->iniSection << "]" << endl;
756 pc->showParams(os);
757 os << endl;
758 }
759 }
760
761
762 //
763 // static method: call cleanup() on all registered contexts
764 //
765 void
766 ParamContext::cleanupAllContexts()
767 {
768 list<ParamContext *>::iterator iter;
769
770 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
771 ParamContext *pc = *iter;
772
773 pc->cleanup();
774 }
775 }
776
777
778 //
779 // static method: call describeParams() on all registered contexts
780 //
781 void
782 ParamContext::describeAllContexts(ostream &os)
783 {
784 list<ParamContext *>::iterator iter;
785
786 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
787 ParamContext *pc = *iter;
788
789 os << "[" << pc->iniSection << "]\n";
790 pc->describeParams(os);
791 os << endl;
792 }
793 }