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