gem5/sim/param.cc
Steve Reinhardt 5a1eb9049d Support for Serializable non-SimObject things like events.
Can now serialize & unserialize DmaRequestEvents and DmaTransferEvents.
Also support serialize/unserialize of pointers to SimObjects and
other Serializable objects.

arch/alpha/alpha_memory.cc:
arch/alpha/alpha_memory.hh:
arch/alpha/isa_traits.hh:
cpu/exec_context.cc:
cpu/exec_context.hh:
cpu/simple_cpu/simple_cpu.hh:
dev/alpha_access.h:
dev/alpha_console.cc:
dev/alpha_console.hh:
dev/console.cc:
dev/console.hh:
    unserialize() now takes a Checkpoint* instead of an IniFile*.
cpu/simple_cpu/simple_cpu.cc:
    unserialize() now takes a Checkpoint* instead of an IniFile*.
    Put ExecContext in its own section so its _status fields doesn't conflict.
sim/eventq.cc:
sim/eventq.hh:
    unserialize() now takes a Checkpoint* instead of an IniFile*.
    Events get serialized by the event queue only if they're marked
    as AutoSerialize... others are assumed to be serialized by something
    else (e.g. an owning SimObject) or to not matter.
sim/param.cc:
    Shift 'const' in case T is a ptr type.
sim/serialize.cc:
sim/serialize.hh:
    Define Checkpoint object to encapsulate everything you need to know
    about a checkpoint.  Use it to allow lookups of named Serializable
    objects (and SimObjects) during unserialization.
    unserialize() now takes a Checkpoint* instead of an IniFile*.

--HG--
extra : convert_revision : 8e6baab32405f8f548bb67a097b2f713296537a5
2003-10-29 21:45:39 -08:00

765 lines
18 KiB
C++

/*
* Copyright (c) 2003 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include <list>
#include <string>
#include <vector>
#include <stdio.h> // for sscanf()
#include <assert.h>
#include "sim/param.hh"
#include "sim/sim_object.hh"
#include "base/inifile.hh"
#include "sim/configfile.hh"
#include "sim/config_node.hh"
#include "base/misc.hh"
#include "base/str.hh"
#include "base/trace.hh"
using namespace std;
////////////////////////////////////////////////////////////////////////
//
// BaseParam member definitions
//
////////////////////////////////////////////////////////////////////////
void
BaseParam::die(const string &err) const
{
context->printErrorProlog(cerr);
cerr << " parameter '" << name << "': "
<< err << endl;
abort();
}
////////////////////////////////////////////////////////////////////////
//
// Param<T> and VectorParam<T> member definitions
//
// We implement parsing & displaying values for various parameter
// types T using a set of overloaded functions:
//
// - parseParam(string s, T &value) parses s into value
// - showParam(ostream &os, T &value) displays value on os
//
// By making these independent functions, we can reuse the same code
// for type T in both Param<T> and VectorParam<T>.
//
// For enum types, the parseParam function requires additional
// arguments, in which case we must specialize the Param<T>::parse and
// VectorParam<T>::parse calls as well.
//
// Type-specific instances come first, followed by more generic
// templated versions and their instantiations.
//
////////////////////////////////////////////////////////////////////////
//
// The base implementations use to_number for parsing and '<<' for
// displaying, suitable for integer types.
//
template <class T>
bool
parseParam(const string &s, T &value)
{
return to_number(s, value);
}
template <class T>
void
showParam(ostream &os, T const &value)
{
os << value;
}
//
// Template specializations:
// - char (8-bit integer)
// - floating-point types
// - bool
// - string
//
// Treat 8-bit ints (chars) as ints on output, not as chars
template <>
void
showParam(ostream &os, const char &value)
{
os << (int)value;
}
template <>
void
showParam(ostream &os, const unsigned char &value)
{
os << (unsigned int)value;
}
// Use sscanf() for FP types as to_number() only handles integers
template <>
bool
parseParam(const string &s, float &value)
{
return (sscanf(s.c_str(), "%f", &value) == 1);
}
template <>
bool
parseParam(const string &s, double &value)
{
return (sscanf(s.c_str(), "%lf", &value) == 1);
}
// Be flexible about what we take for bool
template <>
bool
parseParam(const string &s, bool &value)
{
const string &lower = to_lower(s);
if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") {
value = true;
return true;
}
if (lower == "false" || lower == "f" || lower == "no" || lower == "n") {
value = false;
return true;
}
return false;
}
// Display bools as strings
template <>
void
showParam(ostream &os, const bool &value)
{
os << (value ? "true" : "false");
}
// String requires no processing to speak of
template <>
bool
parseParam(const string &s, string &value)
{
value = s;
return true;
}
//
// End of parseParam/showParam definitions. Now we move on to
// incorporate them into the Param/VectorParam parse() and showValue()
// methods.
//
// These definitions for Param<T>::parse and VectorParam<T>::parse
// work for any type for which parseParam() takes only two arguments
// (i.e., all the fundamental types like int, bool, etc.), thanks to
// overloading.
template <class T>
void
Param<T>::parse(const string &s)
{
if (parseParam(s, value)) {
wasSet = true;
}
else {
string err("could not parse \"");
err += s;
err += "\"";
die(err);
}
}
template <class T>
void
VectorParam<T>::parse(const string &s)
{
vector<string> tokens;
tokenize(tokens, s, ' ');
value.resize(tokens.size());
for (int i = 0; i < tokens.size(); i++) {
// need to parse into local variable to handle vector<bool>,
// for which operator[] returns a special reference class
// that's not the same as 'bool&', (since it's a packed
// vector)
T scalar_value;
if (!parseParam(tokens[i], scalar_value)) {
string err("could not parse \"");
err += s;
err += "\"";
die(err);
}
// assign parsed value to vector
value[i] = scalar_value;
}
wasSet = true;
}
// These definitions for Param<T>::showValue() and
// VectorParam<T>::showValue() work for any type where showParam()
// takes only two arguments (i.e., everything but the SimpleEnum and
// MappedEnum classes).
template <class T>
void
Param<T>::showValue(ostream &os) const
{
showParam(os, value);
}
template <class T>
void
VectorParam<T>::showValue(ostream &os) const
{
for (int i = 0; i < value.size(); i++) {
if (i != 0) {
os << " ";
}
showParam(os, value[i]);
}
}
#ifdef INSURE_BUILD
#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
void Param<type>::showType(ostream &os) const { os << typestr; } \
void VectorParam<type>::showType(ostream &os) const { \
os << "vector of " << typestr; \
} \
template Param<type>; \
template VectorParam<type>;
#else
// instantiate all four methods (parse/show, scalar/vector) for basic
// types that can use the above templates
#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
template bool parseParam<type>(const string &s, type &value); \
template void showParam<type>(ostream &os, type const &value); \
template void Param<type>::parse(const string &); \
template void VectorParam<type>::parse(const string &); \
template void Param<type>::showValue(ostream &) const; \
template void VectorParam<type>::showValue(ostream &) const; \
void Param<type>::showType(ostream &os) const { os << typestr; } \
void VectorParam<type>::showType(ostream &os) const { \
os << "vector of " << typestr; \
}
#endif
INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
INSTANTIATE_PARAM_TEMPLATES(float, "float")
INSTANTIATE_PARAM_TEMPLATES(double, "double")
INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
INSTANTIATE_PARAM_TEMPLATES(string, "string")
#undef INSTANTIATE_PARAM_TEMPLATES
//
// SimpleEnumParam & MappedEnumParam must specialize their parse(),
// showValue(), and showType() methods.
//
//
// SimpleEnumParam & SimpleEnumVectorParam
//
bool
parseEnumParam(const char *const *map, const int num_values,
const string &s, int &value)
{
for (int i = 0; i < num_values; ++i) {
if (s == map[i]) {
value = i;
return true;
}
}
return false;
}
void
showEnumParam(ostream &os,
const char *const *map, const int num_values,
int value)
{
assert(0 <= value && value < num_values);
os << map[value];
}
void
showEnumType(ostream &os,
const char *const *map, const int num_values)
{
os << "{" << map[0];
for (int i = 1; i < num_values; ++i)
os << "," << map[i];
os << "}";
}
//
// MappedEnumParam & MappedEnumVectorParam
//
bool
parseEnumParam(const EnumParamMap *map, const int num_values,
const string &s, int &value)
{
for (int i = 0; i < num_values; ++i) {
if (s == map[i].name) {
value = map[i].value;
return true;
}
}
return false;
}
void
showEnumParam(ostream &os,
const EnumParamMap *map, const int num_values,
int value)
{
for (int i = 0; i < num_values; ++i) {
if (value == map[i].value) {
os << map[i].name;
return;
}
}
// if we can't find a reverse mapping just print the int value
os << value;
}
void
showEnumType(ostream &os,
const EnumParamMap *map, const int num_values)
{
os << "{" << map[0].name;
for (int i = 1; i < num_values; ++i)
os << "," << map[i].name;
os << "}";
}
template <class Map>
void
EnumParam<Map>::parse(const string &s)
{
if (parseEnumParam(map, num_values, s, value)) {
wasSet = true;
} else {
string err("no match for enum string \"");
err += s;
err += "\"";
die(err);
}
}
template <class Map>
void
EnumVectorParam<Map>::parse(const string &s)
{
vector<string> tokens;
tokenize(tokens, s, ' ');
value.resize(tokens.size());
for (int i = 0; i < tokens.size(); i++) {
if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
string err("no match for enum string \"");
err += s;
err += "\"";
die(err);
}
}
wasSet = true;
}
template <class Map>
void
EnumParam<Map>::showValue(ostream &os) const
{
showEnumParam(os, map, num_values, value);
}
template <class Map>
void
EnumVectorParam<Map>::showValue(ostream &os) const
{
for (int i = 0; i < value.size(); i++) {
if (i != 0) {
os << " ";
}
showEnumParam(os, map, num_values, value[i]);
}
}
template <class Map>
void
EnumParam<Map>::showType(ostream &os) const
{
showEnumType(os, map, num_values);
}
template <class Map>
void
EnumVectorParam<Map>::showType(ostream &os) const
{
os << "vector of";
showEnumType(os, map, num_values);
}
template EnumParam<const char *>;
template EnumVectorParam<const char *>;
template EnumParam<EnumParamMap>;
template EnumVectorParam<EnumParamMap>;
////////////////////////////////////////////////////////////////////////
//
// SimObjectBaseParam methods
//
////////////////////////////////////////////////////////////////////////
bool
parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
{
SimObject *obj;
if (to_lower(s) == "null") {
// explicitly set to null by user; assume that's OK
obj = NULL;
}
else {
obj = context->resolveSimObject(s);
if (obj == NULL)
return false;
}
value = obj;
return true;
}
void
SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
{
os << (value ? value->name() : "null");
}
void
SimObjectBaseParam::parse(const string &s, SimObject *&value)
{
if (parseSimObjectParam(context, s, value)) {
wasSet = true;
}
else {
string err("could not resolve object name \"");
err += s;
err += "\"";
die(err);
}
}
void
SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
{
vector<string> tokens;
tokenize(tokens, s, ' ');
value.resize(tokens.size());
for (int i = 0; i < tokens.size(); i++) {
if (!parseSimObjectParam(context, tokens[i], value[i])) {
string err("could not resolve object name \"");
err += s;
err += "\"";
die(err);
}
}
wasSet = true;
}
////////////////////////////////////////////////////////////////////////
//
// ParamContext member definitions
//
////////////////////////////////////////////////////////////////////////
list<ParamContext *> *ParamContext::ctxList = NULL;
ParamContext::ParamContext(const string &_iniSection, bool noAutoParse)
: iniFilePtr(NULL), // initialized on call to parseParams()
iniSection(_iniSection), paramList(NULL)
{
if (!noAutoParse) {
if (ctxList == NULL)
ctxList = new list<ParamContext *>();
(*ctxList).push_back(this);
}
}
void
ParamContext::addParam(BaseParam *param)
{
getParamList()->push_back(param);
}
void
ParamContext::parseParams(IniFile &iniFile)
{
iniFilePtr = &iniFile; // set object member
ParamList::iterator i;
for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
string string_value;
if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
(*i)->parse(string_value);
}
}
}
// Check parameter values for validity & consistency. Default
// implementation is no-op; derive subclass & override to add
// actual functionality here.
void
ParamContext::checkParams()
{
// nada
}
// Clean up context-related objects at end of execution. Default
// implementation is no-op; derive subclass & override to add actual
// functionality here.
void
ParamContext::cleanup()
{
// nada
}
void
ParamContext::describeParams(ostream &os)
{
ParamList::iterator i;
for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
BaseParam *p = *i;
os << p->name << " (";
p->showType(os);
os << "): " << p->description << "\n";
}
}
void
ParamContext::showParams(ostream &os)
{
ParamList::iterator i;
for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
BaseParam *p = *i;
if (p->isValid()) {
os << p->name << "=";
p->showValue(os);
os << endl;
}
else {
os << "// "<< p->name << " not specified" << endl;
}
}
}
void
ParamContext::printErrorProlog(ostream &os)
{
os << "Parameter error in section [" << iniSection << "]: " << endl;
}
//
// Resolve an object name to a SimObject pointer. The object will be
// created as a side-effect if necessary. If the name contains a
// colon (e.g., "iq:IQ"), then the object is local (invisible to
// outside this context). If there is no colon, the name needs to be
// resolved through the configuration hierarchy (only possible for
// SimObjectBuilder objects, which return non-NULL for configNode()).
//
SimObject *
ParamContext::resolveSimObject(const string &_name)
{
// look for a colon
string::size_type i = _name.find(':');
string name = _name;
if (i != string::npos) {
// colon found: local object
// add as child to current node and create it
name = _name.substr(0, i);
string objConfigClassName = _name.substr(i + 1);
getConfigNode()->addChild(name, objConfigClassName);
}
ConfigNode *n = getConfigNode();
return n ? n->resolveSimObject(name) : NULL;
}
//
// static method: call parseParams() on all registered contexts
//
void
ParamContext::parseAllContexts(IniFile &iniFile)
{
list<ParamContext *>::iterator iter;
for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
ParamContext *pc = *iter;
pc->parseParams(iniFile);
}
}
//
// static method: call checkParams() on all registered contexts
//
void
ParamContext::checkAllContexts()
{
list<ParamContext *>::iterator iter;
for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
ParamContext *pc = *iter;
pc->checkParams();
}
}
//
// static method: call showParams() on all registered contexts
//
void
ParamContext::showAllContexts(ostream &os)
{
list<ParamContext *>::iterator iter;
for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
ParamContext *pc = *iter;
os << "[" << pc->iniSection << "]" << endl;
pc->showParams(os);
os << endl;
}
}
//
// static method: call cleanup() on all registered contexts
//
void
ParamContext::cleanupAllContexts()
{
list<ParamContext *>::iterator iter;
for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
ParamContext *pc = *iter;
pc->cleanup();
}
}
//
// static method: call describeParams() on all registered contexts
//
void
ParamContext::describeAllContexts(ostream &os)
{
list<ParamContext *>::iterator iter;
for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
ParamContext *pc = *iter;
os << "[" << pc->iniSection << "]\n";
pc->describeParams(os);
os << endl;
}
}