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