Merge zizzer:/bk/m5 into zeep.eecs.umich.edu:/z/saidi/work/m5
[gem5.git] / sim / param.cc
1 /*
2 * Copyright (c) 2002-2004 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 <list>
31 #include <string>
32 #include <vector>
33 #include <stdio.h> // for sscanf()
34
35 #include <assert.h>
36
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"
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 //
184 // End of parseParam/showParam definitions. Now we move on to
185 // incorporate them into the Param/VectorParam parse() and showValue()
186 // methods.
187 //
188
189 // These definitions for Param<T>::parse and VectorParam<T>::parse
190 // work for any type for which parseParam() takes only two arguments
191 // (i.e., all the fundamental types like int, bool, etc.), thanks to
192 // overloading.
193 template <class T>
194 void
195 Param<T>::parse(const string &s)
196 {
197 if (parseParam(s, value)) {
198 wasSet = true;
199 }
200 else {
201 string err("could not parse \"");
202
203 err += s;
204 err += "\"";
205
206 die(err);
207 }
208 }
209
210 template <class T>
211 void
212 VectorParam<T>::parse(const string &s)
213 {
214 if (s.empty()) {
215 wasSet = true;
216 return;
217 }
218
219 vector<string> tokens;
220
221 tokenize(tokens, s, ' ');
222
223 value.resize(tokens.size());
224
225 for (int i = 0; i < tokens.size(); i++) {
226 // need to parse into local variable to handle vector<bool>,
227 // for which operator[] returns a special reference class
228 // that's not the same as 'bool&', (since it's a packed
229 // vector)
230 T scalar_value;
231 if (!parseParam(tokens[i], scalar_value)) {
232 string err("could not parse \"");
233
234 err += s;
235 err += "\"";
236
237 die(err);
238 }
239
240 // assign parsed value to vector
241 value[i] = scalar_value;
242 }
243
244 wasSet = true;
245 }
246
247 // These definitions for Param<T>::showValue() and
248 // VectorParam<T>::showValue() work for any type where showParam()
249 // takes only two arguments (i.e., everything but the SimpleEnum and
250 // MappedEnum classes).
251 template <class T>
252 void
253 Param<T>::showValue(ostream &os) const
254 {
255 showParam(os, value);
256 }
257
258 template <class T>
259 void
260 VectorParam<T>::showValue(ostream &os) const
261 {
262 for (int i = 0; i < value.size(); i++) {
263 if (i != 0) {
264 os << " ";
265 }
266 showParam(os, value[i]);
267 }
268 }
269
270
271 #ifdef INSURE_BUILD
272 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
273 void Param<type>::showType(ostream &os) const { os << typestr; } \
274 void VectorParam<type>::showType(ostream &os) const { \
275 os << "vector of " << typestr; \
276 } \
277 template Param<type>; \
278 template VectorParam<type>;
279
280 #else
281 // instantiate all four methods (parse/show, scalar/vector) for basic
282 // types that can use the above templates
283 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
284 template bool parseParam<type>(const string &s, type &value); \
285 template void showParam<type>(ostream &os, type const &value); \
286 template void Param<type>::parse(const string &); \
287 template void VectorParam<type>::parse(const string &); \
288 template void Param<type>::showValue(ostream &) const; \
289 template void VectorParam<type>::showValue(ostream &) const; \
290 void Param<type>::showType(ostream &os) const { os << typestr; } \
291 void VectorParam<type>::showType(ostream &os) const { \
292 os << "vector of " << typestr; \
293 }
294 #endif
295
296 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
297 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
298 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
299 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
300 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
301 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
302 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
303 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
304 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
305 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
306
307 INSTANTIATE_PARAM_TEMPLATES(float, "float")
308 INSTANTIATE_PARAM_TEMPLATES(double, "double")
309
310 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
311 INSTANTIATE_PARAM_TEMPLATES(string, "string")
312
313 #undef INSTANTIATE_PARAM_TEMPLATES
314
315 //
316 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
317 // showValue(), and showType() methods.
318 //
319
320 //
321 // SimpleEnumParam & SimpleEnumVectorParam
322 //
323 bool
324 parseEnumParam(const char *const *map, const int num_values,
325 const string &s, int &value)
326 {
327 for (int i = 0; i < num_values; ++i) {
328 if (s == map[i]) {
329 value = i;
330 return true;
331 }
332 }
333
334 return false;
335 }
336
337 void
338 showEnumParam(ostream &os,
339 const char *const *map, const int num_values,
340 int value)
341 {
342 assert(0 <= value && value < num_values);
343 os << map[value];
344 }
345
346 void
347 showEnumType(ostream &os,
348 const char *const *map, const int num_values)
349 {
350 os << "{" << map[0];
351 for (int i = 1; i < num_values; ++i)
352 os << "," << map[i];
353
354 os << "}";
355 }
356
357
358 //
359 // MappedEnumParam & MappedEnumVectorParam
360 //
361 bool
362 parseEnumParam(const EnumParamMap *map, const int num_values,
363 const string &s, int &value)
364 {
365 for (int i = 0; i < num_values; ++i) {
366 if (s == map[i].name) {
367 value = map[i].value;
368 return true;
369 }
370 }
371
372 return false;
373 }
374
375 void
376 showEnumParam(ostream &os,
377 const EnumParamMap *map, const int num_values,
378 int value)
379 {
380 for (int i = 0; i < num_values; ++i) {
381 if (value == map[i].value) {
382 os << map[i].name;
383 return;
384 }
385 }
386
387 // if we can't find a reverse mapping just print the int value
388 os << value;
389 }
390
391 void
392 showEnumType(ostream &os,
393 const EnumParamMap *map, const int num_values)
394 {
395 os << "{" << map[0].name;
396 for (int i = 1; i < num_values; ++i)
397 os << "," << map[i].name;
398
399 os << "}";
400 }
401
402
403 template <class Map>
404 void
405 EnumParam<Map>::parse(const string &s)
406 {
407 if (parseEnumParam(map, num_values, s, value)) {
408 wasSet = true;
409 } else {
410 string err("no match for enum string \"");
411
412 err += s;
413 err += "\"";
414
415 die(err);
416 }
417 }
418
419 template <class Map>
420 void
421 EnumVectorParam<Map>::parse(const string &s)
422 {
423 vector<string> tokens;
424
425 tokenize(tokens, s, ' ');
426
427 value.resize(tokens.size());
428
429 for (int i = 0; i < tokens.size(); i++) {
430 if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
431 string err("no match for enum string \"");
432
433 err += s;
434 err += "\"";
435
436 die(err);
437 }
438 }
439
440 wasSet = true;
441 }
442
443 template <class Map>
444 void
445 EnumParam<Map>::showValue(ostream &os) const
446 {
447 showEnumParam(os, map, num_values, value);
448 }
449
450 template <class Map>
451 void
452 EnumVectorParam<Map>::showValue(ostream &os) const
453 {
454 for (int i = 0; i < value.size(); i++) {
455 if (i != 0) {
456 os << " ";
457 }
458 showEnumParam(os, map, num_values, value[i]);
459 }
460 }
461
462 template <class Map>
463 void
464 EnumParam<Map>::showType(ostream &os) const
465 {
466 showEnumType(os, map, num_values);
467 }
468
469 template <class Map>
470 void
471 EnumVectorParam<Map>::showType(ostream &os) const
472 {
473 os << "vector of";
474 showEnumType(os, map, num_values);
475 }
476
477 template EnumParam<const char *>;
478 template EnumVectorParam<const char *>;
479
480 template EnumParam<EnumParamMap>;
481 template EnumVectorParam<EnumParamMap>;
482
483 ////////////////////////////////////////////////////////////////////////
484 //
485 // SimObjectBaseParam methods
486 //
487 ////////////////////////////////////////////////////////////////////////
488
489 bool
490 parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
491 {
492 SimObject *obj;
493
494 if (to_lower(s) == "null") {
495 // explicitly set to null by user; assume that's OK
496 obj = NULL;
497 }
498 else {
499 obj = context->resolveSimObject(s);
500
501 if (obj == NULL)
502 return false;
503 }
504
505 value = obj;
506 return true;
507 }
508
509
510 void
511 SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
512 {
513 os << (value ? value->name() : "null");
514 }
515
516 void
517 SimObjectBaseParam::parse(const string &s, SimObject *&value)
518 {
519 if (parseSimObjectParam(context, s, value)) {
520 wasSet = true;
521 }
522 else {
523 string err("could not resolve object name \"");
524
525 err += s;
526 err += "\"";
527
528 die(err);
529 }
530 }
531
532 void
533 SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
534 {
535 vector<string> tokens;
536
537 tokenize(tokens, s, ' ');
538
539 value.resize(tokens.size());
540
541 for (int i = 0; i < tokens.size(); i++) {
542 if (!parseSimObjectParam(context, tokens[i], value[i])) {
543 string err("could not resolve object name \"");
544
545 err += s;
546 err += "\"";
547
548 die(err);
549 }
550 }
551
552 wasSet = true;
553 }
554
555 ////////////////////////////////////////////////////////////////////////
556 //
557 // ParamContext member definitions
558 //
559 ////////////////////////////////////////////////////////////////////////
560
561 list<ParamContext *> *ParamContext::ctxList = NULL;
562
563 ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase)
564 : iniFilePtr(NULL), // initialized on call to parseParams()
565 iniSection(_iniSection), paramList(NULL),
566 initPhase(_initPhase)
567 {
568 // Put this context on global list for initialization
569 if (initPhase != NoAutoInit) {
570 if (ctxList == NULL)
571 ctxList = new list<ParamContext *>();
572
573 // keep list sorted by ascending initPhase values
574 list<ParamContext *>::iterator i = ctxList->begin();
575 list<ParamContext *>::iterator end = ctxList->end();
576 for (; i != end; ++i) {
577 if (initPhase <= (*i)->initPhase) {
578 // found where we want to insert
579 break;
580 }
581 }
582 // (fall through case: insert at end)
583 ctxList->insert(i, this);
584 }
585 }
586
587
588 void
589 ParamContext::addParam(BaseParam *param)
590 {
591 getParamList()->push_back(param);
592 }
593
594
595 void
596 ParamContext::parseParams(IniFile &iniFile)
597 {
598 iniFilePtr = &iniFile; // set object member
599
600 ParamList::iterator i;
601
602 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
603 string string_value;
604
605 if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
606 (*i)->parse(string_value);
607 }
608 }
609 }
610
611
612 // Check parameter values for validity & consistency. Default
613 // implementation is no-op; derive subclass & override to add
614 // actual functionality here.
615 void
616 ParamContext::checkParams()
617 {
618 // nada
619 }
620
621
622 // Clean up context-related objects at end of execution. Default
623 // implementation is no-op; derive subclass & override to add actual
624 // functionality here.
625 void
626 ParamContext::cleanup()
627 {
628 // nada
629 }
630
631
632 void
633 ParamContext::describeParams(ostream &os)
634 {
635 ParamList::iterator i;
636
637 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
638 BaseParam *p = *i;
639
640 os << p->name << " (";
641 p->showType(os);
642 os << "): " << p->description << "\n";
643 }
644 }
645
646
647
648 void
649 ParamContext::showParams(ostream &os)
650 {
651 ParamList::iterator i;
652
653 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
654 BaseParam *p = *i;
655
656 if (p->isValid()) {
657 os << p->name << "=";
658 p->showValue(os);
659 os << endl;
660 }
661 else {
662 os << "// "<< p->name << " not specified" << endl;
663 }
664 }
665 }
666
667
668 void
669 ParamContext::printErrorProlog(ostream &os)
670 {
671 os << "Parameter error in section [" << iniSection << "]: " << endl;
672 }
673
674 //
675 // Resolve an object name to a SimObject pointer. The object will be
676 // created as a side-effect if necessary. If the name contains a
677 // colon (e.g., "iq:IQ"), then the object is local (invisible to
678 // outside this context). If there is no colon, the name needs to be
679 // resolved through the configuration hierarchy (only possible for
680 // SimObjectBuilder objects, which return non-NULL for configNode()).
681 //
682 SimObject *
683 ParamContext::resolveSimObject(const string &_name)
684 {
685 // look for a colon
686 string::size_type i = _name.find(':');
687 string name = _name;
688 if (i != string::npos) {
689 // colon found: local object
690 // add as child to current node and create it
691 name = _name.substr(0, i);
692 string objConfigClassName = _name.substr(i + 1);
693 getConfigNode()->addChild(name, objConfigClassName);
694 }
695 ConfigNode *n = getConfigNode();
696 return n ? n->resolveSimObject(name) : NULL;
697 }
698
699
700 //
701 // static method: call parseParams() on all registered contexts
702 //
703 void
704 ParamContext::parseAllContexts(IniFile &iniFile)
705 {
706 list<ParamContext *>::iterator iter;
707
708 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
709 ParamContext *pc = *iter;
710
711 pc->parseParams(iniFile);
712 }
713 }
714
715
716 //
717 // static method: call checkParams() on all registered contexts
718 //
719 void
720 ParamContext::checkAllContexts()
721 {
722 list<ParamContext *>::iterator iter;
723
724 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
725 ParamContext *pc = *iter;
726
727 pc->checkParams();
728 }
729 }
730
731
732 //
733 // static method: call showParams() on all registered contexts
734 //
735 void
736 ParamContext::showAllContexts(ostream &os)
737 {
738 list<ParamContext *>::iterator iter;
739
740 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
741 ParamContext *pc = *iter;
742
743 os << "[" << pc->iniSection << "]" << endl;
744 pc->showParams(os);
745 os << endl;
746 }
747 }
748
749
750 //
751 // static method: call cleanup() on all registered contexts
752 //
753 void
754 ParamContext::cleanupAllContexts()
755 {
756 list<ParamContext *>::iterator iter;
757
758 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
759 ParamContext *pc = *iter;
760
761 pc->cleanup();
762 }
763 }
764
765
766 //
767 // static method: call describeParams() on all registered contexts
768 //
769 void
770 ParamContext::describeAllContexts(ostream &os)
771 {
772 list<ParamContext *>::iterator iter;
773
774 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
775 ParamContext *pc = *iter;
776
777 os << "[" << pc->iniSection << "]\n";
778 pc->describeParams(os);
779 os << endl;
780 }
781 }