Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / include / command_opts.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: command_opts.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
#ifndef COMMAND_OPTS_H__
#define COMMAND_OPTS_H__
/************************************************************************
**
** Copyright (C) 2007, Sun Microsystems, Inc.
**
** Sun considers its source code as an unpublished, proprietary
** trade secret and it is available only under strict license provisions.
** This copyright notice is placed here only to protect Sun in the event
** the source is deemed a published work. Disassembly, decompilation,
** or other means of reducing the object code to human readable form
** is prohibited by the license agreement under which this code is
** provided to the user or company in possession of this copy.
**
*************************************************************************/
#include <sys/types.h>
#include <stdlib.h>
#include <list>
#include <map>
#include <vector>
#include <set>
#include <string>
#include "vcpu.h"
// The CommandOptions, Option, ArgumentOption, and ExclusiveOptions
// classes enable configuration based command line option flag
// parsing. Options with and without values are supported, as well as
// groups of exclusive options (similar to GUI's radio buttons).
//
// An option's initial on-off state may be set, defaulting to off
// (false). By default, an option may appear many times on the
// command line, the last instance taking effect. This behavior can
// be reversed so that an option may appear only once.
//
// Options with argument values are strictly typed and are initialized
// with a default value.
//
// Mutually exclusive options are described in the ExclusiveOptions
// class. The exclusive options are added to the ExclusiveOptions
// object. If one of the exclusive options appears on the command
// line, one of two behaviors occurs. In this case, by default every
// other exclusive option is turned off. Alternatively, if two
// exclusive options appear, the option parser stops with a fatal
// error.
//
// Options (and any derived class such as ArgumentOption) objects are
// added to a CommandOptions object. The CommandOptions object holds
// all the legal options, described by these option objects, and
// supplies a parse() method that takes an argv[] array and scans it
// for matching options. parse() updates the state in the option
// objects, so that their off-on and arguments values can be queried,
// and sets a stl vector of strings to any remaining positional
// arguments.
//
// If parse() succeeds, it returns true. If it fails, it returns
// false and a subsequent call to get_error_msg() will return a
// message describing the error.
class Option
{
public:
friend class ExclusiveOptions;
enum Result {
NOT_FOUND,
ON_OFF_FOUND,
VALUE_FOUND,
PARSE_ERROR
};
enum Repeatable {
REPEATABLE,
NOT_REPEATABLE
};
enum OnOff {
OFF,
ON
};
// Creates a repeatable, initially off option by default
Option(std::string name_,
Repeatable repeatable_ = REPEATABLE,
OnOff on_off_default = OFF) :
name(name_),
on_off(on_off_default),
repeatable(repeatable_),
seen(false)
{}
virtual ~Option() {}
std::string get_name() const { return name; }
bool is_on() const { return on_off == ON; }
bool is_off() const { return on_off == OFF; }
void turn_off() { on_off = OFF; }
Result parse(const std::string& cmd_line_arg, const char* val_str);
virtual std::string get_error_msg() const
{
return error_msg;
}
virtual void print(FILE* fp = stdout) const
{
fprintf(fp, "-%s is %s", get_name().c_str(), is_on() ? "ON" : "OFF");
std::string val_str = print_value();
if (val_str != "")
fprintf(fp, " -- value is is %s", val_str.c_str());
fprintf(fp, "\n");
}
protected:
bool seen;
std::string error_msg;
virtual bool takes_argument() const { return false; }
virtual Result parse_value(const std::string& val_str)
{
fprintf(stderr, "Internal error: called Option::parse_value()\n");
exit(-1);
return Option::PARSE_ERROR;
}
virtual std::string print_value() const
{
return "";
}
private:
Option() :
name(""),
on_off(OFF),
repeatable(REPEATABLE)
{}
const std::string name;
OnOff on_off;
const Repeatable repeatable;
std::list<ExclusiveOptions*> excl_opts;
};
template <typename T>
class ArgumentOption : public Option
{
public:
ArgumentOption(std::string name_,
const T& default_value,
Repeatable repeatable_ = REPEATABLE,
OnOff on_off_default = OFF) :
Option(name_, repeatable_, on_off_default),
value(default_value)
{}
virtual ~ArgumentOption() {}
T get_value() const { return value; }
virtual Result parse_value(const std::string& val_str) = 0;
protected:
T value;
virtual bool takes_argument() const { return true; }
virtual std::string print_value() const = 0;
ArgumentOption() {}
};
class ExclusiveOptions
{
public:
enum Compatible {
COMPATIBLE,
INCOMPATIBLE
};
ExclusiveOptions(Compatible compatible_ = COMPATIBLE) :
compatible(compatible_)
{}
virtual ~ExclusiveOptions() {}
ExclusiveOptions& add(Option& opt)
{
options[opt.get_name()] = &opt;
opt.excl_opts.push_back(this);
return *this;
}
bool update(Option& opt);
std::string get_error_msg() const
{
return error_msg;
}
private:
const Compatible compatible;
std::map<std::string,Option*> options;
std::string error_msg;
};
class UnsignedOption : public ArgumentOption<uint64_t>
{
public:
UnsignedOption(std::string name_,
uint64_t default_value = 0,
Repeatable repeatable_ = REPEATABLE,
uint64_t base_ = 0) :
ArgumentOption(name_, default_value, repeatable_, OFF),
base(base_)
{}
~UnsignedOption() {}
static bool parse_number(const std::string& num_str,
uint64_t& value,
std::string& error_msg,
int base = 0)
{
if (num_str[0] == '-')
{
error_msg = "Leading '-' not allowed with ";
return false;
}
char *endptr;
uint64_t parse_value = strtoull(num_str.c_str(), &endptr, base);
if (*endptr != '\0')
{
error_msg = "Illegal numeric argument passed to ";
return false;
}
value = parse_value;
return true;
}
Result parse_value(const std::string& val_str)
{
if (parse_number(val_str, value, error_msg, base))
return VALUE_FOUND;
else
{
error_msg += "-" + get_name() + "option";
return PARSE_ERROR;
}
}
private:
UnsignedOption() : base(0) {}
const uint64_t base;
std::string print_value() const
{
char buf[100];
sprintf(buf, "0x%llx", value);
return buf;
}
};
class SignedOption : public ArgumentOption<int64_t>
{
public:
SignedOption(std::string name_,
uint64_t default_value = 0,
Repeatable repeatable_ = REPEATABLE,
uint64_t base_ = 0) :
ArgumentOption(name_, default_value, repeatable_, OFF),
base(base_)
{}
~SignedOption() {}
static bool parse_number(const std::string& num_str,
int64_t& value,
std::string& error_msg,
int base = 0)
{
char *endptr;
int64_t parse_value = strtoll(num_str.c_str(), &endptr, base);
if (*endptr != '\0')
{
error_msg = "Illegal numeric argument passed to ";
return false;
}
value = parse_value;
return true;
}
Result parse_value(const std::string& val_str)
{
if (parse_number(val_str, value, error_msg, base))
return VALUE_FOUND;
else
{
error_msg += "-" + get_name() + "option";
return PARSE_ERROR;
}
}
private:
SignedOption() : base(0) {}
const uint64_t base;
std::string print_value() const
{
char buf[100];
sprintf(buf, "%lld", value);
return buf;
}
};
class StringOption : public ArgumentOption<std::string>
{
public:
StringOption(std::string name_,
std::string default_value = "",
Repeatable repeatable_ = REPEATABLE) :
ArgumentOption(name_, default_value, repeatable_, OFF)
{}
~StringOption() {}
Result parse_value(const std::string& val_str)
{
value = val_str;
return VALUE_FOUND;
}
private:
StringOption() {}
std::string print_value() const
{
return value;
}
};
class CpuSet
{
public:
typedef std::set<uint32_t>::iterator iterator;
typedef std::set<uint32_t>::const_iterator const_iterator;
static int get_nr_cpus() { return max_cpu_ndx + 1; }
CpuSet(int singleton_ndx = -1)
{
if (singleton_ndx != -1)
insert(singleton_ndx);
}
virtual ~CpuSet() {}
const_iterator begin() const { return cpu_set.begin(); }
iterator begin() { return cpu_set.begin(); }
const_iterator end() const { return cpu_set.end(); }
iterator end() { return cpu_set.end(); }
CpuSet& insert_all()
{
for (int ndx = 0; ndx < get_nr_cpus(); ++ndx)
insert(ndx);
return *this;
}
CpuSet& clear_all()
{
cpu_set.clear();
return *this;
}
CpuSet& insert(uint32_t ndx, bool* out_of_range = NULL)
{
if (ndx < get_nr_cpus())
{
cpu_set.insert(ndx);
if (out_of_range != NULL)
*out_of_range = false;
}
else if (out_of_range != NULL)
*out_of_range = true;
return *this;
}
CpuSet& insert_mask(uint64_t mask, bool* out_of_range = NULL)
{
bool local_out_of_range = false;
for (int ndx = 0; ndx < 64 && !local_out_of_range; ++ndx)
if (mask & (1ULL << ndx))
insert(ndx, &local_out_of_range);
if (out_of_range != NULL)
*out_of_range = local_out_of_range;
return *this;
}
iterator find(uint32_t ndx, bool* out_of_range = NULL)
{
if (out_of_range != NULL)
*out_of_range = (ndx < get_nr_cpus());
return cpu_set.find(ndx);
}
bool find_one(uint32_t ndx, bool* out_of_range = NULL)
{
if (out_of_range != NULL)
*out_of_range = (ndx < get_nr_cpus());
return find(ndx, out_of_range) != cpu_set.end();
}
bool operator!=(const CpuSet& rhs)
{
return cpu_set != rhs.cpu_set;
}
std::string print() const
{
std::string rtn;
for (const_iterator iter = cpu_set.begin();
iter != cpu_set.end();
++iter)
{
char buf[100];
sprintf(buf, ",%d", *iter);
rtn += buf;
}
return rtn.empty() ? "" : rtn.substr(1);
}
protected:
static int& max_cpu_ndx;
std::set<uint32_t> cpu_set;
};
class CpuOption : public ArgumentOption<CpuSet>
{
public:
enum Singleton {
SINGLETON,
MULTITUDE
};
CpuOption(int cpu_ndx,
Singleton singleton_ = SINGLETON)
:
ArgumentOption("cpu", CpuSet(cpu_ndx)),
singleton(singleton_)
{}
CpuOption(const CpuSet& default_cpuset,
Singleton singleton_ = SINGLETON)
:
ArgumentOption("cpu", default_cpuset),
singleton(singleton_)
{}
~CpuOption() {}
Result parse_value(const std::string& val_str)
{
if (val_str == "all")
{
if (singleton == SINGLETON)
{
error_msg = "Only one cpu can be passed to the -" + get_name() +
" option";
return PARSE_ERROR;
}
value.insert_all();
}
else /* if "all" */
{
value.clear_all();
std::string t;
int start=0;
int end;
while (1)
{
end=val_str.find(",", start);
std::string tok = val_str.substr(start, (end-start));
std::string left;
std::string right;
std::string stride="1";
int pos = tok.find("..");
left = tok.substr(0, pos);
if (pos != std::string::npos)
{
std::string rhs = tok.substr(pos+2);
// further tokenize rhs by ":"
int cpos = rhs.find(":");
right = rhs.substr(0, cpos);
if (cpos != std::string::npos)
stride = rhs.substr(cpos+1);
}
else
{
right = left;
}
Result rv = insert_values(left, right, stride);
if (rv == PARSE_ERROR) return rv;
if (end == std::string::npos) break;
start = end+1;
} // while more tokens
} /* some or "all" cpus specified? */
return VALUE_FOUND;
}
private:
CpuOption() {}
Singleton singleton;
std::string print_value() const
{
return value.print();
}
Result insert_values(std::string leftstr, std::string rightstr, std::string stridestr) {
uint64_t left, right, stride;
UnsignedOption uso(get_name());
Result rv;;
rv = uso.parse_value(leftstr);
if (rv != VALUE_FOUND) return rv;
left = uso.get_value();
rv = uso.parse_value(rightstr);
if (rv != VALUE_FOUND) return rv;
right = uso.get_value();
rv = uso.parse_value(stridestr);
if (rv != VALUE_FOUND) return rv;
stride = uso.get_value();
if (stride == 0) {
error_msg = "stride must be a positive number";
return PARSE_ERROR;
}
// fprintf(stderr, "insert_values: left=%lld right=%lld stride=%lld\n", left, right, stride);
char buf[512];
if (left > right) {
sprintf(buf, "upper limit of range (%d) cannot be less than lower limit (%d)",
left, right);
error_msg = buf;
return PARSE_ERROR;
}
uint64_t v;
for (v=left; v<=right; v += stride) {
bool out_of_bounds = false;
// fprintf(stderr, "parse_value: trying to insert value %d\n", v);
value.insert(v, &out_of_bounds);
if (out_of_bounds) {
error_msg = "Cpu number passed to -" + get_name() + " too big";
return PARSE_ERROR;
}
}
return VALUE_FOUND;
} // insert_values
};
class OptionList
{
public:
typedef std::list<Option*>::iterator iterator;
iterator begin() { return opt_list.begin(); }
iterator end() { return opt_list.end(); }
OptionList& push_front(Option* option)
{
opt_list.push_front(option);
return *this;
}
private:
std::list<Option*> opt_list;
};
class AddressingOptions : public OptionList
{
public:
enum AddrType {
PA,
RA,
VA
};
AddressingOptions(AddrType default_addr_type_)
:
pa_opt("pa", Option::REPEATABLE),
ra_opt("ra", Option::REPEATABLE),
va_opt("va", Option::REPEATABLE),
context_id("context_id", 0),
partition_id("partition_id", 0),
pa_ra_va_exclusive(ExclusiveOptions::INCOMPATIBLE),
default_addr_type(default_addr_type_)
{
pa_ra_va_exclusive.add(pa_opt).add(ra_opt).add(va_opt);
push_front(&pa_opt);
push_front(&ra_opt);
push_front(&va_opt);
push_front(&context_id);
push_front(&partition_id);
}
Option pa_opt;
Option ra_opt;
Option va_opt;
UnsignedOption context_id;
UnsignedOption partition_id;
Vcpu::TranslateMode translate_mode()
{
if (pa_opt.is_on())
{
return Vcpu::TRANSLATE_PA_TO_PA;
}
else if (ra_opt.is_on())
{
if (partition_id.is_on())
return Vcpu::TRANSLATE_RA_TO_PA_PID;
else
return Vcpu::TRANSLATE_RA_TO_PA;
}
else if (va_opt.is_on())
{
if (context_id.is_off())
// ignore partition_id in this case
return Vcpu::TRANSLATE_VA_TO_PA;
else if (partition_id.is_off())
return Vcpu::TRANSLATE_VA_TO_PA_CTX;
else
return Vcpu::TRANSLATE_VA_TO_PA_CTX_PID;
}
else
{
switch (default_addr_type)
{
case PA: return Vcpu::TRANSLATE_PA_TO_PA;
case RA: return Vcpu::TRANSLATE_RA_TO_PA;
case VA: return Vcpu::TRANSLATE_VA_TO_PA;
}
return Vcpu::TRANSLATE_VA_TO_PA;
}
}
private:
ExclusiveOptions pa_ra_va_exclusive;
AddrType default_addr_type;
};
class CommandOptions
{
public:
CommandOptions() {}
virtual ~CommandOptions() {}
bool parse(const char* cmd_line,
std::vector<std::string>& positional_args);
bool parse(int argc,
const char** argv,
std::vector<std::string>& positional_args);
std::string get_error_msg() const
{
return error_msg;
}
CommandOptions& add(Option& opt)
{
options[opt.get_name()] = &opt;
return *this;
}
CommandOptions& add(OptionList& opt_list)
{
for (OptionList::iterator iter = opt_list.begin();
iter != opt_list.end();
++iter)
add(**iter);
return *this;
}
void print(FILE* fp = stdout) const
{
for (std::map<std::string,Option*>::const_iterator iter = options.begin();
iter != options.end();
++iter)
iter->second->print();
}
private:
std::map<std::string,Option*> options;
std::string error_msg;
};
#endif /* COMMAND_OPTS_H__ */