Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / include / command_opts.h
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: command_opts.h
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23#ifndef COMMAND_OPTS_H__
24#define COMMAND_OPTS_H__
25
26/************************************************************************
27**
28** Copyright (C) 2007, Sun Microsystems, Inc.
29**
30** Sun considers its source code as an unpublished, proprietary
31** trade secret and it is available only under strict license provisions.
32** This copyright notice is placed here only to protect Sun in the event
33** the source is deemed a published work. Disassembly, decompilation,
34** or other means of reducing the object code to human readable form
35** is prohibited by the license agreement under which this code is
36** provided to the user or company in possession of this copy.
37**
38*************************************************************************/
39
40#include <sys/types.h>
41#include <stdlib.h>
42#include <list>
43#include <map>
44#include <vector>
45#include <set>
46#include <string>
47
48#include "vcpu.h"
49
50// The CommandOptions, Option, ArgumentOption, and ExclusiveOptions
51// classes enable configuration based command line option flag
52// parsing. Options with and without values are supported, as well as
53// groups of exclusive options (similar to GUI's radio buttons).
54//
55// An option's initial on-off state may be set, defaulting to off
56// (false). By default, an option may appear many times on the
57// command line, the last instance taking effect. This behavior can
58// be reversed so that an option may appear only once.
59//
60// Options with argument values are strictly typed and are initialized
61// with a default value.
62//
63// Mutually exclusive options are described in the ExclusiveOptions
64// class. The exclusive options are added to the ExclusiveOptions
65// object. If one of the exclusive options appears on the command
66// line, one of two behaviors occurs. In this case, by default every
67// other exclusive option is turned off. Alternatively, if two
68// exclusive options appear, the option parser stops with a fatal
69// error.
70//
71// Options (and any derived class such as ArgumentOption) objects are
72// added to a CommandOptions object. The CommandOptions object holds
73// all the legal options, described by these option objects, and
74// supplies a parse() method that takes an argv[] array and scans it
75// for matching options. parse() updates the state in the option
76// objects, so that their off-on and arguments values can be queried,
77// and sets a stl vector of strings to any remaining positional
78// arguments.
79//
80// If parse() succeeds, it returns true. If it fails, it returns
81// false and a subsequent call to get_error_msg() will return a
82// message describing the error.
83
84
85class Option
86{
87 public:
88
89 friend class ExclusiveOptions;
90
91 enum Result {
92 NOT_FOUND,
93 ON_OFF_FOUND,
94 VALUE_FOUND,
95 PARSE_ERROR
96 };
97
98 enum Repeatable {
99 REPEATABLE,
100 NOT_REPEATABLE
101 };
102
103 enum OnOff {
104 OFF,
105 ON
106 };
107
108 // Creates a repeatable, initially off option by default
109 Option(std::string name_,
110 Repeatable repeatable_ = REPEATABLE,
111 OnOff on_off_default = OFF) :
112 name(name_),
113 on_off(on_off_default),
114 repeatable(repeatable_),
115 seen(false)
116 {}
117
118 virtual ~Option() {}
119
120 std::string get_name() const { return name; }
121
122 bool is_on() const { return on_off == ON; }
123 bool is_off() const { return on_off == OFF; }
124
125 void turn_off() { on_off = OFF; }
126
127 Result parse(const std::string& cmd_line_arg, const char* val_str);
128
129 virtual std::string get_error_msg() const
130 {
131 return error_msg;
132 }
133
134 virtual void print(FILE* fp = stdout) const
135 {
136 fprintf(fp, "-%s is %s", get_name().c_str(), is_on() ? "ON" : "OFF");
137 std::string val_str = print_value();
138 if (val_str != "")
139 fprintf(fp, " -- value is is %s", val_str.c_str());
140 fprintf(fp, "\n");
141 }
142
143 protected:
144 bool seen;
145 std::string error_msg;
146 virtual bool takes_argument() const { return false; }
147
148 virtual Result parse_value(const std::string& val_str)
149 {
150 fprintf(stderr, "Internal error: called Option::parse_value()\n");
151 exit(-1);
152 return Option::PARSE_ERROR;
153 }
154
155 virtual std::string print_value() const
156 {
157 return "";
158 }
159
160 private:
161 Option() :
162 name(""),
163 on_off(OFF),
164 repeatable(REPEATABLE)
165 {}
166
167 const std::string name;
168 OnOff on_off;
169 const Repeatable repeatable;
170 std::list<ExclusiveOptions*> excl_opts;
171};
172
173
174template <typename T>
175class ArgumentOption : public Option
176{
177 public:
178 ArgumentOption(std::string name_,
179 const T& default_value,
180 Repeatable repeatable_ = REPEATABLE,
181 OnOff on_off_default = OFF) :
182 Option(name_, repeatable_, on_off_default),
183 value(default_value)
184 {}
185
186 virtual ~ArgumentOption() {}
187
188 T get_value() const { return value; }
189
190 virtual Result parse_value(const std::string& val_str) = 0;
191
192 protected:
193 T value;
194
195 virtual bool takes_argument() const { return true; }
196
197 virtual std::string print_value() const = 0;
198
199 ArgumentOption() {}
200};
201
202
203class ExclusiveOptions
204{
205 public:
206 enum Compatible {
207 COMPATIBLE,
208 INCOMPATIBLE
209 };
210
211 ExclusiveOptions(Compatible compatible_ = COMPATIBLE) :
212 compatible(compatible_)
213 {}
214
215 virtual ~ExclusiveOptions() {}
216
217 ExclusiveOptions& add(Option& opt)
218 {
219 options[opt.get_name()] = &opt;
220 opt.excl_opts.push_back(this);
221 return *this;
222 }
223
224 bool update(Option& opt);
225
226 std::string get_error_msg() const
227 {
228 return error_msg;
229 }
230
231 private:
232 const Compatible compatible;
233 std::map<std::string,Option*> options;
234
235 std::string error_msg;
236};
237
238class UnsignedOption : public ArgumentOption<uint64_t>
239{
240 public:
241 UnsignedOption(std::string name_,
242 uint64_t default_value = 0,
243 Repeatable repeatable_ = REPEATABLE,
244 uint64_t base_ = 0) :
245 ArgumentOption(name_, default_value, repeatable_, OFF),
246 base(base_)
247 {}
248
249 ~UnsignedOption() {}
250
251 static bool parse_number(const std::string& num_str,
252 uint64_t& value,
253 std::string& error_msg,
254 int base = 0)
255 {
256 if (num_str[0] == '-')
257 {
258 error_msg = "Leading '-' not allowed with ";
259 return false;
260 }
261
262 char *endptr;
263 uint64_t parse_value = strtoull(num_str.c_str(), &endptr, base);
264 if (*endptr != '\0')
265 {
266 error_msg = "Illegal numeric argument passed to ";
267 return false;
268 }
269 value = parse_value;
270 return true;
271 }
272
273 Result parse_value(const std::string& val_str)
274 {
275 if (parse_number(val_str, value, error_msg, base))
276 return VALUE_FOUND;
277 else
278 {
279 error_msg += "-" + get_name() + "option";
280 return PARSE_ERROR;
281 }
282 }
283
284 private:
285 UnsignedOption() : base(0) {}
286
287 const uint64_t base;
288
289 std::string print_value() const
290 {
291 char buf[100];
292 sprintf(buf, "0x%llx", value);
293 return buf;
294 }
295};
296
297
298class SignedOption : public ArgumentOption<int64_t>
299{
300 public:
301 SignedOption(std::string name_,
302 uint64_t default_value = 0,
303 Repeatable repeatable_ = REPEATABLE,
304 uint64_t base_ = 0) :
305 ArgumentOption(name_, default_value, repeatable_, OFF),
306 base(base_)
307 {}
308
309 ~SignedOption() {}
310
311 static bool parse_number(const std::string& num_str,
312 int64_t& value,
313 std::string& error_msg,
314 int base = 0)
315 {
316 char *endptr;
317 int64_t parse_value = strtoll(num_str.c_str(), &endptr, base);
318 if (*endptr != '\0')
319 {
320 error_msg = "Illegal numeric argument passed to ";
321 return false;
322 }
323 value = parse_value;
324 return true;
325 }
326
327 Result parse_value(const std::string& val_str)
328 {
329 if (parse_number(val_str, value, error_msg, base))
330 return VALUE_FOUND;
331 else
332 {
333 error_msg += "-" + get_name() + "option";
334 return PARSE_ERROR;
335 }
336 }
337
338 private:
339 SignedOption() : base(0) {}
340
341 const uint64_t base;
342
343 std::string print_value() const
344 {
345 char buf[100];
346 sprintf(buf, "%lld", value);
347 return buf;
348 }
349};
350
351
352class StringOption : public ArgumentOption<std::string>
353{
354 public:
355 StringOption(std::string name_,
356 std::string default_value = "",
357 Repeatable repeatable_ = REPEATABLE) :
358 ArgumentOption(name_, default_value, repeatable_, OFF)
359 {}
360
361 ~StringOption() {}
362
363 Result parse_value(const std::string& val_str)
364 {
365 value = val_str;
366 return VALUE_FOUND;
367 }
368
369 private:
370 StringOption() {}
371
372 std::string print_value() const
373 {
374 return value;
375 }
376};
377
378class CpuSet
379{
380 public:
381
382 typedef std::set<uint32_t>::iterator iterator;
383 typedef std::set<uint32_t>::const_iterator const_iterator;
384
385 static int get_nr_cpus() { return max_cpu_ndx + 1; }
386
387 CpuSet(int singleton_ndx = -1)
388 {
389 if (singleton_ndx != -1)
390 insert(singleton_ndx);
391 }
392
393 virtual ~CpuSet() {}
394
395 const_iterator begin() const { return cpu_set.begin(); }
396 iterator begin() { return cpu_set.begin(); }
397 const_iterator end() const { return cpu_set.end(); }
398 iterator end() { return cpu_set.end(); }
399
400 CpuSet& insert_all()
401 {
402 for (int ndx = 0; ndx < get_nr_cpus(); ++ndx)
403 insert(ndx);
404 return *this;
405 }
406
407 CpuSet& clear_all()
408 {
409 cpu_set.clear();
410 return *this;
411 }
412
413 CpuSet& insert(uint32_t ndx, bool* out_of_range = NULL)
414 {
415 if (ndx < get_nr_cpus())
416 {
417 cpu_set.insert(ndx);
418 if (out_of_range != NULL)
419 *out_of_range = false;
420 }
421 else if (out_of_range != NULL)
422 *out_of_range = true;
423
424 return *this;
425 }
426
427 CpuSet& insert_mask(uint64_t mask, bool* out_of_range = NULL)
428 {
429 bool local_out_of_range = false;
430
431 for (int ndx = 0; ndx < 64 && !local_out_of_range; ++ndx)
432 if (mask & (1ULL << ndx))
433 insert(ndx, &local_out_of_range);
434
435 if (out_of_range != NULL)
436 *out_of_range = local_out_of_range;
437
438 return *this;
439 }
440
441 iterator find(uint32_t ndx, bool* out_of_range = NULL)
442 {
443 if (out_of_range != NULL)
444 *out_of_range = (ndx < get_nr_cpus());
445
446 return cpu_set.find(ndx);
447 }
448
449 bool find_one(uint32_t ndx, bool* out_of_range = NULL)
450 {
451 if (out_of_range != NULL)
452 *out_of_range = (ndx < get_nr_cpus());
453
454 return find(ndx, out_of_range) != cpu_set.end();
455 }
456
457 bool operator!=(const CpuSet& rhs)
458 {
459 return cpu_set != rhs.cpu_set;
460 }
461
462 std::string print() const
463 {
464 std::string rtn;
465
466 for (const_iterator iter = cpu_set.begin();
467 iter != cpu_set.end();
468 ++iter)
469 {
470 char buf[100];
471 sprintf(buf, ",%d", *iter);
472 rtn += buf;
473 }
474 return rtn.empty() ? "" : rtn.substr(1);
475 }
476
477 protected:
478
479 static int& max_cpu_ndx;
480
481 std::set<uint32_t> cpu_set;
482};
483
484class CpuOption : public ArgumentOption<CpuSet>
485{
486 public:
487 enum Singleton {
488 SINGLETON,
489 MULTITUDE
490 };
491
492 CpuOption(int cpu_ndx,
493 Singleton singleton_ = SINGLETON)
494 :
495 ArgumentOption("cpu", CpuSet(cpu_ndx)),
496 singleton(singleton_)
497 {}
498
499 CpuOption(const CpuSet& default_cpuset,
500 Singleton singleton_ = SINGLETON)
501 :
502 ArgumentOption("cpu", default_cpuset),
503 singleton(singleton_)
504 {}
505
506 ~CpuOption() {}
507
508 Result parse_value(const std::string& val_str)
509 {
510 if (val_str == "all")
511 {
512 if (singleton == SINGLETON)
513 {
514 error_msg = "Only one cpu can be passed to the -" + get_name() +
515 " option";
516 return PARSE_ERROR;
517 }
518
519 value.insert_all();
520 }
521 else /* if "all" */
522 {
523 value.clear_all();
524
525 std::string t;
526 int start=0;
527 int end;
528 while (1)
529 {
530 end=val_str.find(",", start);
531
532 std::string tok = val_str.substr(start, (end-start));
533
534 std::string left;
535 std::string right;
536 std::string stride="1";
537
538 int pos = tok.find("..");
539 left = tok.substr(0, pos);
540 if (pos != std::string::npos)
541 {
542 std::string rhs = tok.substr(pos+2);
543 // further tokenize rhs by ":"
544 int cpos = rhs.find(":");
545 right = rhs.substr(0, cpos);
546 if (cpos != std::string::npos)
547 stride = rhs.substr(cpos+1);
548 }
549 else
550 {
551 right = left;
552 }
553
554 Result rv = insert_values(left, right, stride);
555 if (rv == PARSE_ERROR) return rv;
556
557
558 if (end == std::string::npos) break;
559 start = end+1;
560 } // while more tokens
561
562 } /* some or "all" cpus specified? */
563
564 return VALUE_FOUND;
565 }
566
567 private:
568 CpuOption() {}
569
570 Singleton singleton;
571
572 std::string print_value() const
573 {
574 return value.print();
575 }
576
577 Result insert_values(std::string leftstr, std::string rightstr, std::string stridestr) {
578 uint64_t left, right, stride;
579 UnsignedOption uso(get_name());
580
581 Result rv;;
582
583 rv = uso.parse_value(leftstr);
584 if (rv != VALUE_FOUND) return rv;
585 left = uso.get_value();
586
587 rv = uso.parse_value(rightstr);
588 if (rv != VALUE_FOUND) return rv;
589 right = uso.get_value();
590
591 rv = uso.parse_value(stridestr);
592 if (rv != VALUE_FOUND) return rv;
593 stride = uso.get_value();
594
595 if (stride == 0) {
596 error_msg = "stride must be a positive number";
597 return PARSE_ERROR;
598 }
599 // fprintf(stderr, "insert_values: left=%lld right=%lld stride=%lld\n", left, right, stride);
600
601 char buf[512];
602 if (left > right) {
603 sprintf(buf, "upper limit of range (%d) cannot be less than lower limit (%d)",
604 left, right);
605 error_msg = buf;
606 return PARSE_ERROR;
607 }
608 uint64_t v;
609 for (v=left; v<=right; v += stride) {
610 bool out_of_bounds = false;
611 // fprintf(stderr, "parse_value: trying to insert value %d\n", v);
612 value.insert(v, &out_of_bounds);
613 if (out_of_bounds) {
614 error_msg = "Cpu number passed to -" + get_name() + " too big";
615 return PARSE_ERROR;
616 }
617 }
618
619 return VALUE_FOUND;
620 } // insert_values
621};
622
623
624class OptionList
625{
626 public:
627 typedef std::list<Option*>::iterator iterator;
628 iterator begin() { return opt_list.begin(); }
629 iterator end() { return opt_list.end(); }
630
631 OptionList& push_front(Option* option)
632 {
633 opt_list.push_front(option);
634 return *this;
635 }
636
637 private:
638 std::list<Option*> opt_list;
639};
640
641class AddressingOptions : public OptionList
642{
643 public:
644 enum AddrType {
645 PA,
646 RA,
647 VA
648 };
649
650 AddressingOptions(AddrType default_addr_type_)
651 :
652 pa_opt("pa", Option::REPEATABLE),
653 ra_opt("ra", Option::REPEATABLE),
654 va_opt("va", Option::REPEATABLE),
655 context_id("context_id", 0),
656 partition_id("partition_id", 0),
657 pa_ra_va_exclusive(ExclusiveOptions::INCOMPATIBLE),
658 default_addr_type(default_addr_type_)
659 {
660 pa_ra_va_exclusive.add(pa_opt).add(ra_opt).add(va_opt);
661
662 push_front(&pa_opt);
663 push_front(&ra_opt);
664 push_front(&va_opt);
665 push_front(&context_id);
666 push_front(&partition_id);
667 }
668
669 Option pa_opt;
670 Option ra_opt;
671 Option va_opt;
672 UnsignedOption context_id;
673 UnsignedOption partition_id;
674
675
676 Vcpu::TranslateMode translate_mode()
677 {
678 if (pa_opt.is_on())
679 {
680 return Vcpu::TRANSLATE_PA_TO_PA;
681 }
682 else if (ra_opt.is_on())
683 {
684 if (partition_id.is_on())
685 return Vcpu::TRANSLATE_RA_TO_PA_PID;
686 else
687 return Vcpu::TRANSLATE_RA_TO_PA;
688 }
689 else if (va_opt.is_on())
690 {
691 if (context_id.is_off())
692 // ignore partition_id in this case
693 return Vcpu::TRANSLATE_VA_TO_PA;
694 else if (partition_id.is_off())
695 return Vcpu::TRANSLATE_VA_TO_PA_CTX;
696 else
697 return Vcpu::TRANSLATE_VA_TO_PA_CTX_PID;
698 }
699 else
700 {
701 switch (default_addr_type)
702 {
703 case PA: return Vcpu::TRANSLATE_PA_TO_PA;
704 case RA: return Vcpu::TRANSLATE_RA_TO_PA;
705 case VA: return Vcpu::TRANSLATE_VA_TO_PA;
706 }
707 return Vcpu::TRANSLATE_VA_TO_PA;
708 }
709 }
710
711 private:
712 ExclusiveOptions pa_ra_va_exclusive;
713 AddrType default_addr_type;
714};
715
716class CommandOptions
717{
718 public:
719 CommandOptions() {}
720 virtual ~CommandOptions() {}
721
722 bool parse(const char* cmd_line,
723 std::vector<std::string>& positional_args);
724
725 bool parse(int argc,
726 const char** argv,
727 std::vector<std::string>& positional_args);
728
729 std::string get_error_msg() const
730 {
731 return error_msg;
732 }
733
734 CommandOptions& add(Option& opt)
735 {
736 options[opt.get_name()] = &opt;
737 return *this;
738 }
739
740 CommandOptions& add(OptionList& opt_list)
741 {
742 for (OptionList::iterator iter = opt_list.begin();
743 iter != opt_list.end();
744 ++iter)
745 add(**iter);
746
747 return *this;
748 }
749
750 void print(FILE* fp = stdout) const
751 {
752 for (std::map<std::string,Option*>::const_iterator iter = options.begin();
753 iter != options.end();
754 ++iter)
755 iter->second->print();
756 }
757
758 private:
759 std::map<std::string,Option*> options;
760
761 std::string error_msg;
762};
763
764#endif /* COMMAND_OPTS_H__ */