/* * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood * 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. */ /* * Type.cc * * Description: See Type.hh * * $Id$ * */ #include "mem/slicc/symbols/Type.hh" #include "mem/slicc/generator/fileio.hh" #include "mem/gems_common/Map.hh" #include "mem/slicc/symbols/StateMachine.hh" Type::Type(string id, const Location& location, const Map& pairs, StateMachine* machine_ptr) : Symbol(id, location, pairs) { if (machine_ptr == NULL) { m_c_id = id; } else if (isExternal() || isPrimitive()) { if (existPair("external_name")) { m_c_id = lookupPair("external_name"); } else { m_c_id = id; } } else { m_c_id = machine_ptr->toString() + "_" + id; // Append with machine name } if(existPair("desc")){ m_desc = lookupPair("desc"); } else { m_desc = "No description avaliable"; } // check for interface that this Type implements if(existPair("interface")) { string interface = lookupPair("interface"); if(interface == "Message" || interface == "NetworkMessage") { addPair("message", "yes"); } if(interface == "NetworkMessage") { addPair("networkmessage", "yes"); } } // FIXME - all of the following id comparisons are fragile hacks if ((getIdent() == "CacheMemory") || (getIdent() == "NewCacheMemory") || (getIdent() == "TLCCacheMemory") || (getIdent() == "DNUCACacheMemory") || (getIdent() == "DNUCABankCacheMemory") || (getIdent() == "L2BankCacheMemory") || (getIdent() == "CompressedCacheMemory") || (getIdent() == "PrefetchCacheMemory")) { addPair("cache", "yes"); } if ((getIdent() == "TBETable") || (getIdent() == "DNUCATBETable") || (getIdent() == "DNUCAStopTable")) { addPair("tbe", "yes"); } if ((getIdent() == "NewTBETable")) { addPair("newtbe", "yes"); } if ((getIdent() == "TimerTable")) { addPair("timer", "yes"); } if ((getIdent() == "DirectoryMemory")) { addPair("dir", "yes"); } if ((getIdent() == "PersistentTable")) { addPair("persistent", "yes"); } if ((getIdent() == "Prefetcher")) { addPair("prefetcher", "yes"); } if ((getIdent() == "DNUCA_Movement")) { addPair("mover", "yes"); } if (id == "MachineType") { m_isMachineType = true; } else { m_isMachineType = false; } } // Return false on error bool Type::dataMemberAdd(string id, Type* type_ptr, Map& pairs, string* init_code) { if (dataMemberExist(id)) { return false; // Error } else { m_data_member_map.add(id, type_ptr); m_data_member_ident_vec.insertAtBottom(id); m_data_member_type_vec.insertAtBottom(type_ptr); m_data_member_pairs_vec.insertAtBottom(pairs); m_data_member_init_code_vec.insertAtBottom(init_code); } return true; } string Type::methodId(string name, const Vector& param_type_vec) { string paramStr = ""; for (int i = 0; i < param_type_vec.size(); i++) { paramStr += "_"+param_type_vec[i]->cIdent(); } return name+paramStr; } bool Type::methodAdd(string name, Type* return_type_ptr, const Vector& param_type_vec) { string id = methodId(name, param_type_vec); if (methodExist(id)) { return false; // Error } else { m_method_return_type_map.add(id, return_type_ptr); m_method_param_type_map.add(id, param_type_vec); return true; } } bool Type::enumAdd(string id, Map pairs_map) { if (enumExist(id)) { return false; } else { m_enum_map.add(id, true); m_enum_vec.insertAtBottom(id); m_enum_pairs.insertAtBottom(pairs_map); // Add default if (!existPair("default")) { addPair("default", cIdent()+"_NUM"); } return true; } } void Type::writeCFiles(string path) const { if (isExternal()) { // Do nothing } else if (isEnumeration()) { printEnumH(path); printEnumC(path); } else { // User defined structs and messages printTypeH(path); printTypeC(path); } } void Type::printTypeH(string path) const { ostringstream out; int size = m_data_member_type_vec.size(); string type_name = cIdent(); // Identifier for the type in C // Header out << "/** \\file " << type_name << ".hh" << endl; out << " * " << endl; out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl; out << " */" << endl; out << endl; out << "#ifndef " << type_name << "_H" << endl; out << "#define " << type_name << "_H" << endl; out << endl; // Include all of the #includes needed out << "#include \"mem/ruby/common/Global.hh\"" << endl; out << "#include \"mem/gems_common/Allocator.hh\"" << endl; for (int i=0; i < size; i++) { Type* type = m_data_member_type_vec[i]; if (!type->isPrimitive()) { out << "#include \"mem/protocol/" << type->cIdent() << ".hh" << "\"" << endl; } } string interface = ""; if(existPair("interface")) { interface = lookupPair("interface"); out << "#include \"mem/protocol/" << interface << ".hh\"" << endl; } // Class definition out << "class " << type_name; if(interface != "") { out << " : public " << interface ; } out << " {" << endl; out << "public:" << endl; // ******** Default constructor ******** out << " " << type_name << "() " << endl; // Call superclass constructor if (interface != "") { out << " : " << interface << "()" << endl; } out << " {" << endl; if(!isGlobal()) { for (int i=0; i < size; i++) { Type* type_ptr = m_data_member_type_vec[i]; string id = m_data_member_ident_vec[i]; if (m_data_member_pairs_vec[i].exist("default")) { // look for default value string default_value = m_data_member_pairs_vec[i].lookup("default"); out << " m_" << id << " = " << default_value << "; // default for this field " << endl; } else if (type_ptr->hasDefault()) { // Look for the type default string default_value = type_ptr->getDefault(); out << " m_" << id << " = " << default_value << "; // default value of " << type_ptr->cIdent() << endl; } else { out << " // m_" << id << " has no default" << endl; } } } // end of if(!isGlobal()) out << " }" << endl; // ******** Default destructor ******** out << " "; out << "~" << type_name << "() { };" << endl; // ******** Full init constructor ******** if(! isGlobal()) { out << " " << type_name << "("; for (int i=0; i < size; i++) { if (i != 0) { out << ", "; } Type* type = m_data_member_type_vec[i]; string id = m_data_member_ident_vec[i]; out << "const " << type->cIdent() << "& local_" << id; } out << ")" << endl; // Call superclass constructor if (interface != "") { out << " : " << interface << "()" << endl; } out << " {" << endl; for (int i=0; i < size; i++) { Type* type_ptr = m_data_member_type_vec[i]; string id = m_data_member_ident_vec[i]; out << " m_" << id << " = local_" << id << ";" << endl; if (m_data_member_pairs_vec[i].exist("nextLineCallHack")) { string next_line_value = m_data_member_pairs_vec[i].lookup("nextLineCallHack"); out << " m_" << id << next_line_value << ";" << endl; } } out << " }" << endl; } // end of if(!isGlobal()) // bobba - //******** Partial init constructor ******** //** Constructor needs only the first n-1 data members for init //** HACK to create objects with partially specified data members //** Need to get rid of this and use hierarchy instead // if(! isGlobal()) { // out << " " << type_name << "("; // for (int i=0; i < size-1; i++) { // if (i != 0) { // out << ", "; // } // Type* type = m_data_member_type_vec[i]; // string id = m_data_member_ident_vec[i]; // out << "const " << type->cIdent() << "& local_" << id; // } // out << ")" << endl; // // Call superclass constructor // if (interface != "") { // out << " : " << interface << "()" << endl; // } // out << " {" << endl; // for (int i=0; i < size-1; i++) { // Type* type_ptr = m_data_member_type_vec[i]; // string id = m_data_member_ident_vec[i]; // out << " m_" << id << " = local_" << id << ";" << endl; // if (m_data_member_pairs_vec[i].exist("nextLineCallHack")) { // string next_line_value = m_data_member_pairs_vec[i].lookup("nextLineCallHack"); // out << " m_" << id << next_line_value << ";" << endl; // } // } // out << " }" << endl; // } // end of if(!isGlobal()) // ******** Message member functions ******** // FIXME: those should be moved into slicc file, slicc should support more of // the c++ class inheritance if (isMessage()) { out << " Message* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); }" << endl; out << " void destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); }" << endl; out << " static Allocator<" << type_name << ">* s_allocator_ptr;" << endl; out << " static void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<" << type_name << ">; }}" << endl; } if(!isGlobal()) { // const Get methods for each field out << " // Const accessors methods for each field" << endl; for (int i=0; i < size; i++) { Type* type_ptr = m_data_member_type_vec[i]; string type = type_ptr->cIdent(); string id = m_data_member_ident_vec[i]; out << "/** \\brief Const accessor method for " << id << " field." << endl; out << " * \\return " << id << " field" << endl; out << " */" << endl; out << " const " << type << "& get" << id << "() const { return m_" << id << "; }" << endl; } out << endl; // Non-const Get methods for each field out << " // Non const Accessors methods for each field" << endl; for (int i=0; i < size; i++) { Type* type_ptr = m_data_member_type_vec[i]; string type = type_ptr->cIdent(); string id = m_data_member_ident_vec[i]; out << "/** \\brief Non-const accessor method for " << id << " field." << endl; out << " * \\return " << id << " field" << endl; out << " */" << endl; out << " " << type << "& get" << id << "() { return m_" << id << "; }" << endl; } out << endl; // Set methods for each field out << " // Mutator methods for each field" << endl; for (int i=0; i < size; i++) { Type* type_ptr = m_data_member_type_vec[i]; string type = type_ptr->cIdent(); string id = m_data_member_ident_vec[i]; out << "/** \\brief Mutator method for " << id << " field */" << endl; out << " void set" << id << "(const " << type << "& local_" << id << ") { m_" << id << " = local_" << id << "; }" << endl; } out << endl; } // end of if(!isGlobal()) out << " void print(ostream& out) const;" << endl; out << "//private:" << endl; // Data members for each field for (int i=0; i < size; i++) { if (!m_data_member_pairs_vec[i].exist("abstract")) { out << " "; // global structure if(isGlobal()) out << "static const "; Type* type = m_data_member_type_vec[i]; string id = m_data_member_ident_vec[i]; out << type->cIdent() << " m_" << id; // init value string* init_code = m_data_member_init_code_vec[i]; if(init_code) { // only global structure can have init value here assert(isGlobal()); out << " = " << *init_code << " "; } out << ";"; if (m_data_member_pairs_vec[i].exist("desc")) { string desc = m_data_member_pairs_vec[i].lookup("desc"); out << " /**< " << desc << "*/"; } out << endl; } } out << "};" << endl; // End class out << "// Output operator declaration" << endl; out << "ostream& operator<<(ostream& out, const " << type_name << "& obj);" << endl; out << endl; out << "// Output operator definition" << endl; out << "extern inline" << endl; out << "ostream& operator<<(ostream& out, const " << type_name << "& obj)" << endl; out << "{" << endl; out << " obj.print(out);" << endl; out << " out << flush;" << endl; out << " return out;" << endl; out << "}" << endl; out << endl; out << "#endif // " << type_name << "_H" << endl; // Write it out conditionally_write_file(path + type_name + ".hh", out); } void Type::printTypeC(string path) const { ostringstream out; int size = m_data_member_type_vec.size(); string type_name = cIdent(); // Identifier for the type in C // Header out << "/** \\file " << type_name << ".cc" << endl; out << " * " << endl; out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl; out << " */" << endl; out << endl; out << "#include \"mem/protocol/" << type_name << ".hh\"" << endl; out << endl; if (isMessage()) { out << "Allocator<" << type_name << ">* " << type_name << "::s_allocator_ptr = NULL;" << endl; } out << "/** \\brief Print the state of this object */" << endl; out << "void " << type_name << "::print(ostream& out) const" << endl; out << "{" << endl; out << " out << \"[" << type_name << ": \";" << endl; // For each field for (int i=0; i < size; i++) { string id = m_data_member_ident_vec[i]; out << " out << \"" << id << "=\" << m_" << id << " << \" \";" << endl; } if (isMessage()) { out << " out << \"" << "Time" << "=\" << getTime()" << " << \" \";" << endl; } // Trailer out << " out << \"]\";" << endl; out << "}" << endl; // Write it out conditionally_write_file(path + type_name + ".cc", out); } void Type::printEnumH(string path) const { ostringstream out; int size = m_enum_vec.size(); string type_name = cIdent(); // Identifier for the type in C string type_desc = desc(); // Header out << "/** \\file " << type_name << ".hh" << endl; out << " * " << endl; out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl; out << " */" << endl; out << "#ifndef " << type_name << "_H" << endl; out << "#define " << type_name << "_H" << endl; out << endl; // Include all of the #includes needed out << "#include \"mem/ruby/common/Global.hh\"" << endl; if (m_isMachineType) { out << "#include \"mem/ruby/config/RubyConfig.hh\"" << endl << endl; } out << endl; // Class definition out << "/** \\enum " << type_name << endl; out << " * \\brief " << type_desc << endl; out << " */" << endl; out << "enum " << type_name << " {" << endl; out << " " << type_name << "_FIRST," << endl; // For each field for(int i = 0; i < size; i++ ) { string id = m_enum_vec[i]; string description; if(m_enum_pairs[i].exist("desc")){ description = m_enum_pairs[i].lookup("desc"); } else { description = "No description avaliable"; } if (i == 0) { out << " " << type_name << "_" << id << " = " << type_name << "_FIRST, /**< " << description << " */" << endl; } else { out << " " << type_name << "_" << id << ", /**< " << description << " */" << endl; } } out << " " << type_name << "_NUM" << endl; out << "};" << endl; // Code to convert from a string to the enumeration out << type_name << " string_to_" << type_name << "(const string& str);" << endl; // Code to convert state to a string out << "string " << type_name << "_to_string(const " << type_name << "& obj);" << endl; // Code to increment an enumeration type out << type_name << " &operator++( " << type_name << " &e);" << endl; // MachineType hack used to set the base component id for each Machine if (m_isMachineType) { out << "int " << type_name << "_base_level(const " << type_name << "& obj);" << endl; out << "int " << type_name << "_base_number(const " << type_name << "& obj);" << endl; out << "int " << type_name << "_base_count(const " << type_name << "& obj);" << endl; out << "int " << type_name << "_chip_count(const " << type_name << "& obj, NodeID chipID);" << endl; for(int i = 0; i < size; i++ ) { string id = m_enum_vec[i]; out << "#define MACHINETYPE_" << id << " 1" << endl; } cout << endl; } // Trailer out << "ostream& operator<<(ostream& out, const " << type_name << "& obj);" << endl; out << endl; out << "#endif // " << type_name << "_H" << endl; // Write the file conditionally_write_file(path + type_name + ".hh", out); } void Type::printEnumC(string path) const { ostringstream out; int size = m_enum_vec.size(); string type_name = cIdent(); // Identifier for the type in C // Header out << "/** \\file " << type_name << ".hh" << endl; out << " * " << endl; out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl; out << " */" << endl; out << endl; out << "#include \"mem/protocol/" << type_name << ".hh\"" << endl; out << endl; // Code for output operator out << "ostream& operator<<(ostream& out, const " << type_name << "& obj)" << endl; out << "{" << endl; out << " out << " << type_name << "_to_string(obj);" << endl; out << " out << flush;" << endl; out << " return out;" << endl; out << "}" << endl; // Code to convert state to a string out << endl; out << "string " << type_name << "_to_string(const " << type_name << "& obj)" << endl; out << "{" << endl; out << " switch(obj) {" << endl; // For each field for( int i = 0; i MachineNames; for( int i = 0; i