/* * Copyright (c) 2002-2005 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. * * Authors: Steve Reinhardt */ #ifndef __SIM_PARAM_HH__ #define __SIM_PARAM_HH__ #include #include #include #include #include "sim/startup.hh" // forward decls class IniFile; class BaseParam; class SimObject; // // The context of a parameter definition... usually a subclass of // SimObjectBuilder (which derives from ParamContext), but abstracted // here to support more global simulator control parameters as well. // class ParamContext : protected StartupCallback { protected: // .ini file (database) for parameter lookup... initialized on call // to parseParams() IniFile *iniFilePtr; // .ini file section for parameter lookup const std::string iniSection; typedef std::vector ParamList; // list of parameters defined in this context ParamList *paramList; ParamList *getParamList() { if (!paramList) paramList = new ParamList; return paramList; } public: /// Constructor. /// @param _iniSection Name of .ini section corresponding to this context. /// @param _initPhase Initialization phase (see InitPhase). ParamContext(const std::string &_iniSection); virtual ~ParamContext() {} // add a parameter to the context... called from the parameter // object's constructor (see BaseParam::BaseParam()) void addParam(BaseParam *); // call parse() on all params in this context to convert string // representations to parameter values virtual void parseParams(IniFile &iniFile); // Check parameter values for validity & consistency. Default // implementation is no-op; derive subclass & override to add // actual functionality here virtual void checkParams(); // Clean up at end of execution: close file descriptors, etc. // Default implementation is no-op; derive subclass & override to // add actual functionality here virtual void cleanup(); // dump parameter descriptions void describeParams(std::ostream &); // Display the parameters & values used void showParams(std::ostream &); // print context information for parameter error virtual void printErrorProlog(std::ostream &); // generate the name for this instance of this context (used as a // prefix to create unique names in resolveSimObject() virtual const std::string &getInstanceName() { return iniSection; } }; // // Base class for all parameter objects // class BaseParam { public: ParamContext *context; std::string name; std::string description; // text description for help message bool wasSet; // true if parameter was set by user bool hasDefault; // true if parameter has default value BaseParam(ParamContext *_context, const std::string &_name, const std::string &_description, bool _hasDefault) : context(_context), name(_name), description(_description), wasSet(false), hasDefault(_hasDefault) { context->addParam(this); } virtual ~BaseParam() {} // a parameter is valid only if its value was set by the user or // it has a default value bool isValid() const { return (wasSet || hasDefault); } // set value by parsing string virtual void parse(const std::string &s) = 0; // display value to stream virtual void showValue(std::ostream &) const = 0; // display type to stream virtual void showType(std::ostream &) const = 0; // signal parse or usage error virtual void die(const std::string &err) const; }; // // Template classes to specialize parameters to specific types. // // Param is for single-valued (scalar) parameters of type T. // VectorParam is for multi-valued (vector) parameters of type T. // These are specified in the .ini file as a space-delimited list of // arguments. // template class Param : public BaseParam { protected: T value; public: // Param with default value: set value to default Param(ParamContext *context, const std::string &name, const std::string &description, T dfltValue) : BaseParam(context, name, description, true), value(dfltValue) { } // Param with no default value: leave value uninitialized Param(ParamContext *context, const std::string &name, const std::string &description) : BaseParam(context, name, description, false) { } virtual ~Param() {} operator T&() { // if we attempt to reference an invalid parameter (i.e., one // with no default value that was not set by the user), die. if (!isValid()) die("not found"); return value; } T returnValue() const { return value; } // display value to stream virtual void showValue(std::ostream &os) const; // display type to stream virtual void showType(std::ostream &) const; // set value by parsing string virtual void parse(const std::string &s); }; // // Template class for vector-valued parameters (lists) // template class VectorParam : public BaseParam { protected: std::vector value; public: typedef typename std::vector::size_type size_type; // Param with default value: set value to default VectorParam(ParamContext *context, const std::string &name, const std::string &description, const std::vector &dfltValue) : BaseParam(context, name, description, true), value(dfltValue) { } // Param with no default value: leave value uninitialized VectorParam(ParamContext *context, const std::string &name, const std::string &description) : BaseParam(context, name, description, false) { } virtual ~VectorParam() {} // basic vector access methods size_type size() const { if (!isValid()) die("not found"); return value.size(); } const T &operator[](size_type n) const { if (!isValid()) die("not found"); return value[n]; } // return reference to value vector operator std::vector&() { if (!isValid()) die("not found"); return value; } // display value to stream virtual void showValue(std::ostream &os) const; // display type to stream virtual void showType(std::ostream &) const; // set value by parsing string virtual void parse(const std::string &s); }; // // Specialization of Param and VectorParam to handle // enumerated types is done in two ways, using SimpleEnumParam and // MappedEnumParam (and their vector counterparts, // SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam // takes an array of strings and maps them to integers based on array // index. MappedEnumParam takes an array of string-to-int mappings, // allowing for mapping strings to non-contiguous integer values, or // mapping multiple strings to the same integer value. // // Both SimpleEnumParam and MappedEnumParam are implemented using a // single template class, EnumParam, which takes the type of the map // as a parameter (const char * or EnumParamMap). Similarly, // SimpleEnumVectorParam and MappedEnumVectorParam are both // implemented using EnumVectorParam. // template class EnumParam : public Param { const int num_values; const Map *map; public: // Param with default value: set value to default EnumParam(ParamContext *context, const std::string &name, const std::string &description, const Map *_map, int _num_values, int dfltValue) : Param(context, name, description, dfltValue), num_values(_num_values), map(_map) { } // Param with no default value: leave value uninitialized EnumParam(ParamContext *context, const std::string &name, const std::string &description, const Map *_map, int _num_values) : Param(context, name, description), num_values(_num_values), map(_map) { } virtual ~EnumParam() {} // display value to stream virtual void showValue(std::ostream &os) const; // display type to stream virtual void showType(std::ostream &) const; // set value by parsing string virtual void parse(const std::string &s); }; // // Vector counterpart to SimpleEnumParam // template class EnumVectorParam : public VectorParam { const int num_values; const Map *map; public: // Param with default value: set value to default EnumVectorParam(ParamContext *context, const std::string &name, const std::string &description, const Map *_map, int _num_values, std::vector &dfltValue) : VectorParam(context, name, description, dfltValue), num_values(_num_values), map(_map) { } // Param with no default value: leave value uninitialized EnumVectorParam(ParamContext *context, const std::string &name, const std::string &description, const Map *_map, int _num_values) : VectorParam(context, name, description), num_values(_num_values), map(_map) { } virtual ~EnumVectorParam() {} // display value to stream virtual void showValue(std::ostream &os) const; // display type to stream virtual void showType(std::ostream &) const; // set value by parsing string virtual void parse(const std::string &s); }; // Specialize EnumParam for a particular enumeration type ENUM // (automates casting to get value of enum type) template class SimpleEnumParam : public EnumParam { public: SimpleEnumParam(ParamContext *context, const std::string &name, const std::string &description, const char **_map, int _num_values, ENUM dfltValue) : EnumParam(context, name, description, _map, _num_values, (int)dfltValue) { } SimpleEnumParam(ParamContext *context, const std::string &name, const std::string &description, const char **_map, int _num_values) : EnumParam(context, name, description, _map, _num_values) { } operator ENUM() const { if (!isValid()) die("not found"); return (ENUM)value; } }; // Specialize EnumParam for a particular enumeration type ENUM // (automates casting to get value of enum type) template class SimpleEnumVectorParam : public EnumVectorParam { public: // skip default value constructor: too much pain to convert // vector initializer to vector SimpleEnumVectorParam(ParamContext *context, const std::string &name, const std::string &description, const char **_map, int _num_values) : EnumVectorParam(context, name, description, _map, _num_values) { } ENUM operator[](size_type n) { if (!isValid()) die("not found"); return (ENUM)value[n]; } }; // // Handle enums via string-to-int map (see comment above). // // An array of string-to-int mappings must be supplied using the // following type. typedef struct { const char *name; int value; } EnumParamMap; // Specialize EnumParam for a particular enumeration type ENUM // (automates casting to get value of enum type) template class MappedEnumParam : public EnumParam { public: MappedEnumParam(ParamContext *context, const std::string &name, const std::string &description, const EnumParamMap *_map, int _num_values, ENUM dfltValue) : EnumParam(context, name, description, _map, _num_values, (int)dfltValue) { } MappedEnumParam(ParamContext *context, const std::string &name, const std::string &description, const EnumParamMap *_map, int _num_values) : EnumParam(context, name, description, _map, _num_values) { } operator ENUM() { if (!isValid()) die("not found"); return (ENUM)value[this->n]; } }; // Specialize EnumParam for a particular enumeration type ENUM // (automates casting to get value of enum type) template class MappedEnumVectorParam : public EnumVectorParam { public: // skip default value constructor: too much pain to convert // vector initializer to vector MappedEnumVectorParam(ParamContext *context, const std::string &name, const std::string &description, const EnumParamMap *_map, int _num_values) : EnumVectorParam(context, name, description, _map, _num_values) { } ENUM operator[](size_type n) { if (!isValid()) die("not found"); return (ENUM)value[n]; } }; // // Parameters that point to other simulation objects (e.g. caches, // busses, etc.) are handled by specializing SimObjectBaseParam to the // specific subtype. The main purpose of SimObjectBaseParam is to // provide a place to stick several helper functions common to all // SimObject-derived parameters. // class SimObjectBaseParam : public BaseParam { public: SimObjectBaseParam(ParamContext *context, const std::string &name, const std::string &description, bool hasDefault) : BaseParam(context, name, description, hasDefault) { } virtual ~SimObjectBaseParam() {} // helper function for SimObjectParam::showValue() void showValue(std::ostream &os, SimObject *obj) const; // helper function for SimObjectParam::parse() void parse(const std::string &s, SimObject *&value); // helper function for SimObjectParam::parse() void parse(const std::string &s, std::vector&value_vec); }; // // Parameter to a specific type of SimObject. Note that T must be a // pointer to a class derived from SimObject (e.g., ). // template class SimObjectParam; template class SimObjectParam : public SimObjectBaseParam { protected: T *value; public: // initialization w/o default SimObjectParam(ParamContext *context, const std::string &name, const std::string &description) : SimObjectBaseParam(context, name, description, false) { } // initialization wit=h default SimObjectParam(ParamContext *context, const std::string &name, const std::string &description, T *dfltValue) : SimObjectBaseParam(context, name, description, true), value(dfltValue) { } virtual ~SimObjectParam() {} // convert to pointer operator T*() { if (!isValid()) die("not found"); return value; } T *operator->() const { if (!isValid()) die("not found"); return value; } // display value to stream virtual void showValue(std::ostream &os) const { SimObjectBaseParam::showValue(os, value); } // display type to stream: see REGISTER_SIM_OBJECT macro in // sim_object.hh for declaration virtual void showType(std::ostream &os) const; // set value by parsing string virtual void parse(const std::string &s) { SimObject *so_ptr; // first parse to generic SimObject * SimObjectBaseParam::parse(s, so_ptr); // now dynamic_cast to specific derived type value = dynamic_cast(so_ptr); // check for failure of dynamic_cast if (value == NULL && so_ptr != NULL) die("not of appropriate type"); } }; // // Vector counterpart to SimObjectParam // template class SimObjectVectorParam; template class SimObjectVectorParam : public SimObjectBaseParam { protected: std::vector value; public: typedef typename std::vector::size_type size_type; SimObjectVectorParam(ParamContext *context, const std::string &name, const std::string &description) : SimObjectBaseParam(context, name, description, false) { } SimObjectVectorParam(ParamContext *context, const std::string &name, const std::string &description, std::vector dfltValue) : SimObjectBaseParam(context, name, description, true), value(dfltValue) { } virtual ~SimObjectVectorParam() {} // basic vector access methods size_type size() const { if (!isValid()) die("not found"); return value.size(); } T *&operator[](size_type n) { if (!isValid()) die("not found"); return value[n]; } // return reference to value vector operator std::vector&() { if (!isValid()) die("not found"); return value; } // display value to stream virtual void showValue(std::ostream &os) const { for (int i = 0; i < value.size(); i++) { if (i != 0) os << " "; SimObjectBaseParam::showValue(os, value[i]); } } // display type to stream: see virtual void showType(std::ostream &os) const; // set value by parsing string virtual void parse(const std::string &s) { std::vector so_ptr_vec; // first parse to generic SimObject * vector (from SimObjectBaseParam) SimObjectBaseParam::parse(s, so_ptr_vec); value.resize(so_ptr_vec.size()); for (int i = 0; i < so_ptr_vec.size(); ++i) { // now dynamic_cast to specific derived type value[i] = dynamic_cast(so_ptr_vec[i]); // check for failure of dynamic_cast if (value[i] == NULL && so_ptr_vec[i] != NULL) die("not of appropriate type"); } } }; // // Macro to define showType() methods for SimObjectParam & // SimObjectVectorParam. Can't do this automatically as it requires a // string name for the type, which you can't get from a template // argument. For concrete derived SimObject types, this macro is // automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh). // #define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \ template<> \ void \ SimObjectParam::showType(std::ostream &os) const \ { \ os << CLASS_NAME; \ } \ \ template<> \ void \ SimObjectVectorParam::showType(std::ostream &os) const \ { \ os << "vector of " << CLASS_NAME; \ } // // Declarations for low-level parsing & displaying functions. These // are used internally, but should not be used directly by clients of // the parameter mechanism, but are declared here so they can be // shared with the serialization code (see sim/serialize.cc). template bool parseParam(const std::string &str, T &data); template void showParam(std::ostream &os, const T &data); void parseTime(const std::vector &time, struct tm *tm); #endif // _SIM_PARAM_HH_