CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch13/src/L1Trigger/GlobalMuonTrigger/src/L1MuGMTLUT.cc

Go to the documentation of this file.
00001 //-------------------------------------------------
00002 //
00003 //   \class L1MuGMTLUT
00009 //
00010 //   $Date: 2007/03/23 18:51:35 $
00011 //   $Revision: 1.5 $
00012 //
00013 //   Author :
00014 //   H. Sakulin            HEPHY Vienna
00015 //
00016 //   Migrated to CMSSW:
00017 //   I. Mikulec
00018 //
00019 //--------------------------------------------------
00020 
00021 //---------------
00022 // C++ Headers --
00023 //---------------
00024 
00025 #include <L1Trigger/GlobalMuonTrigger/src/L1MuGMTLUT.h>
00026 
00027 #include <iostream>
00028 #include <fstream>
00029 #include <sstream>
00030 
00031 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00032 
00033 using namespace std;
00034 
00035 L1MuGMTLUT::~L1MuGMTLUT() {
00036   if (! m_UseLookupFunction ) {
00037     
00038     // de-allocate vectors
00039     // no destuction needed for vector< vector <unsigned> >
00040 
00041     // for (int i=0;i < m_NLUTS; i++) 
00042     //   m_Contents[i].clear();
00043     // m_Contents.clear();
00044   }
00045 }
00046 
00047 void L1MuGMTLUT::Init(const char* name, const vector<string>& instances, 
00048                       const vector<port>& in_widths, const vector<port>& out_widths, 
00049                       unsigned vme_addr_width, bool distrRAM) 
00050 {
00051   m_name = name;
00052   m_InstNames = instances;
00053   m_NLUTS = instances.size();
00054 
00055   m_Inputs = in_widths;
00056   m_TotalInWidth = 0; 
00057   for (unsigned i=0; i< in_widths.size(); i++) m_TotalInWidth += in_widths[i].second;
00058 
00059   m_Outputs = out_widths;
00060   m_TotalOutWidth = 0; 
00061   for (unsigned i=0; i< out_widths.size(); i++) m_TotalOutWidth += out_widths[i].second;
00062 
00063   m_vme_addr_width = vme_addr_width;
00064   m_distrRAM = distrRAM;
00065 
00066   if (m_distrRAM && (m_TotalInWidth != vme_addr_width) ) {
00067     edm::LogWarning("AddressMismatch")
00068          << "L1MuGMTLUT::Init(): for distributed RAM the GMT (Input) address width " 
00069          << "has to match the VME address width. Core Generation will not work."; 
00070   }
00071 
00072   m_initialized = true; 
00073 }
00074 
00075 
00076 void L1MuGMTLUT::Save(const char* path) {
00077   if (! m_initialized) {
00078     edm::LogWarning("LUTNotInitialized") << "L1MuGMTLUT::Save: LUT not initialized. ";
00079     return;
00080   }
00081 
00082   m_saveFlag = true;
00083 
00084   ofstream of(path);
00085   of << "// This is a CMS L1 Global Muon Trigger .lut file. " << endl;
00086   of << "//  " << endl;
00087   of << "// It defines a set of look-up-tables(LUTs) of the same type (same inputs and outputs) but" << endl;
00088   of << "// with different default contents. For example a certain type of LUT can have different" << endl;
00089   of << "// default values for DT for RPC and for CSC muons. " << endl;
00090   of << "//  " << endl;
00091   of << "// NAME           gives the name of the LUT. It should match the base name (name without '.lut')" << endl;
00092   of << "//                of the LUT file." << endl;
00093   of << "//                When deriving a C++ sub-class the name is used case sensitive." << endl;
00094   of << "//                In generated VHDL code the name is used in lower case." << endl;
00095   of << "//  " << endl;
00096   of << "// INSTANCES      is the list of instances of the LUT with different default values." << endl;
00097   of << "//                the lists consists of identifiers for each of the instances separated by spaces." << endl;
00098   of << "//                the identifiers can be made up of characters that are valid in VHDL lables. " << endl;
00099   of << "//                In the VHDL code they are used to label the different instances." << endl;
00100   of << "//  " << endl;
00101   of << "//                In C++ and VHDL the instance of a LUT is selected by an integer index where 0 " << endl;
00102   of << "//                corresponds to the leftmost identifier. Integer indices are also used in the CONTENTS_XX" << endl;
00103   of << "//                statements in this file." << endl;
00104   of << "//  " << endl;
00105   of << "// LUT_INPUTS     is the (space-separated) list of inputs of the LUT. Each input is specified in the form" << endl;
00106   of << "//                <input_name>(<number_of_bits>) where <input_name> is the name of the input and" << endl;
00107   of << "//                <number_of_bits> is the number of bits of the input. <input_name> has to be a valid" << endl;
00108   of << "//                identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
00109   of << "//  " << endl;
00110   of << "//                All LUT inputs together make up the address of the corresponding memory." << endl;
00111   of << "//                The first input in the list corresponds to the most-significant bits of the address." << endl;
00112   of << "//  " << endl;
00113   of << "// LUT_OUTPUTS    is the (space-separated) list of outputs of the LUT. Each output is specified in the form" << endl;
00114   of << "//                <output_name>(<number_of_bits>) where <output_name> is the name of the output and" << endl;
00115   of << "//                <number_of_bits> is the number of bits of the output. <output_name> has to be a valid" << endl;
00116   of << "//                identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
00117   of << "//  " << endl;
00118   of << "//                All LUT outputs together make up the data of the corresponding memory." << endl;
00119   of << "//                The first output in the list corresponds to the most-significant data bits." << endl;
00120   of << "//  " << endl;
00121   of << "// VME_ADDR_WIDTH is the address width of the LUT memory when accessed via VME. When the LUT " << endl;
00122   of << "//                is implemented as dual-port block RAM, the VME address with can be different " << endl;
00123   of << "//                from the address width given by the sum of the input widths. It can be larger or" << endl;
00124   of << "//                smaller by a factor of 2^n. When the LUT is implemented as dual-port distributed RAM," << endl;
00125   of << "//                the VME address width has to match the input width. " << endl;
00126   of << "//  " << endl;
00127   of << "// DISTRIBUTED_RAM is 1 if the LUT is to be implemented in distributed RAM and 0 for Block RAM " << endl;
00128   of << "//                 Note that for distributed RAM the address width on the GMT side (sum of input widths)" << endl;
00129   of << "//                 has to match the vme_addr_width" << endl;
00130   of << "//  " << endl;
00131   of << "// CONTENTS_XX    specifies the default contents of instance with index XX (see INSTANCES)." << endl;
00132   of << "//                contents are specified as decimal numbers, one number per line." << endl;
00133   of << "//  " << endl;
00134   of << "// Hannes Sakulin / HEPHY Vienna, 2003" << endl;
00135   of << "// "<< endl;
00136   
00137   of << "NAME = " << m_name << endl;
00138   of << "INSTANCES =" ;
00139   for (unsigned i=0; i<m_InstNames.size(); i++) of << " " << m_InstNames[i];
00140   of << endl;
00141   of << "LUT_INPUTS = " << PortDecoder(m_Inputs).str() <<  endl;
00142   of << "LUT_OUTPUTS = " << PortDecoder(m_Outputs).str() << endl;
00143   of << "VME_ADDR_WIDTH = " << m_vme_addr_width << endl;
00144   of << "DISTRIBUTED_RAM = " << (m_distrRAM?"1":"0") << endl;
00145   for (int i=0; i<m_NLUTS; i++) {
00146     of << "// " << m_InstNames[i] << endl;
00147     of << "CONTENTS_" << i << " = ";
00148     for (unsigned addr = 0; addr < (unsigned) (1<<m_TotalInWidth); addr ++) {
00149       of << LookupPacked (i, addr) << endl;
00150     }
00151     of << endl;
00152   }
00153 
00154   m_saveFlag = false;
00155 
00156 }
00157 
00158 
00159 // Rules for file
00160 //
00161 // NAME = VALUE1 [VALUE2 [...]]
00162 // All header variables have to be set before first contents variable
00163 // comments start with "//" and go up to end of line
00164 // 
00165 // when writing back, comments will be save first
00166 
00167 
00168 //--------------------------------------------------------------------------------
00169 
00170 void L1MuGMTLUT::Set (int idx, unsigned address, unsigned value) {
00171   if (! m_initialized) {
00172      edm::LogWarning("LUTNotInitialized") << "L1MuGMTLUT::Set: LUT not initialized. ";
00173     return;
00174   }
00175 
00176   if ( idx >= m_NLUTS ) {
00177     edm::LogWarning("LUTRangeViolation") << "L1MuGMTLUT::Set: LUT index exceeds range (0 to " << ( m_NLUTS -1 ) << ").";
00178     return;
00179   }
00180   if ( address >= (unsigned)(1 << m_TotalInWidth) ) {
00181     edm::LogWarning("LUTRangeViolation") << "Error in L1MuGMTLUT::Set: LUT input exceeds range (0 to " << ( (1 << m_TotalInWidth) -1 ) << ").";
00182     return;
00183   }
00184   if ( value >= (unsigned)(1 << m_TotalOutWidth) ) {
00185     edm::LogWarning("LUTRangeViolation") << "Error in L1MuGMTLUT::Set: LUT output exceeds range (0 to " << ( (1 << m_TotalOutWidth) -1 ) << ")." ;
00186     return;
00187   }
00188   m_Contents[idx][address] = value;
00189 }
00190  
00191 
00192 
00193 void L1MuGMTLUT::Load(const char* path) {
00194   string lf_name("");
00195   int lf_NLUTS=0; 
00196   vector <string> lf_InstNames;
00197   vector <port> lf_Inputs;
00198   vector <port> lf_Outputs;
00199   unsigned lf_vme_addr_width=0;
00200   bool lf_distrRAM=false;
00201   vector<string> lf_comments;
00202 
00203   ifstream in (path);
00204   const int sz=1000; char buf[sz];
00205 
00206 
00207   // read header
00208   
00209   while ( in.getline(buf, sz) ) {
00210     string line(buf);
00211     string::size_type i=0;
00212     if ( (i=line.find("//")) != string::npos) {
00213       lf_comments.push_back( line.substr(i) ); // save comments
00214       line.erase(i); // and strip
00215     }
00216     L1MuGMTLUTHelpers::Tokenizer tok("=", line);
00217     if (tok.size() == 2) {
00218       L1MuGMTLUTHelpers::replace(tok[0], " ","", false); // skip spaces
00219       L1MuGMTLUTHelpers::replace(tok[0], "\t","", false); // skip tabs
00220 
00221       L1MuGMTLUTHelpers::replace(tok[1], "\t", " ", false); // convert tabs to spaces
00222       L1MuGMTLUTHelpers::replace(tok[1], "  ", " ", true); // skip multiple spaces
00223       tok[1].erase(0, tok[1].find_first_not_of(" ")); // skip leading spaces
00224       tok[1].erase(tok[1].find_last_not_of(" ")+1); // skip trailing spaces
00225             
00226       if (tok[0] == "NAME") lf_name = tok[1];
00227       else if (tok[0] == "INSTANCES") { lf_InstNames = L1MuGMTLUTHelpers::Tokenizer(" ",tok[1]); lf_NLUTS = lf_InstNames.size();}
00228       else if (tok[0] == "LUT_INPUTS") lf_Inputs = PortDecoder(tok[1]);
00229       else if (tok[0] == "LUT_OUTPUTS") lf_Outputs = PortDecoder(tok[1]); 
00230       else if (tok[0] == "VME_ADDR_WIDTH") lf_vme_addr_width = atoi(tok[1].c_str()); 
00231       else if (tok[0] == "DISTRIBUTED_RAM") lf_distrRAM = ( atoi(tok[1].c_str()) == 1 ); 
00232     }
00233     if (tok[0].find("CONTENTS") != string::npos) break;
00234   }
00235 
00236   if (!m_initialized) { // then initialize
00237     Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);    
00238   }
00239   else { // verify compatibility
00240     if (m_name != lf_name ||
00241         m_InstNames != lf_InstNames ||
00242         m_Inputs != lf_Inputs ||
00243         m_Outputs != lf_Outputs ||
00244         m_vme_addr_width != lf_vme_addr_width ||
00245         m_distrRAM != lf_distrRAM) {
00246       edm::LogWarning("LUTParmasMismatch") 
00247           << "L1MuGMTLUT::Load: error: parameters in file do not match configuration of LUT. Load failed.";
00248       return;
00249     }
00250   }
00251   
00252   if (m_UseLookupFunction) {
00253     // allocate vectors
00254     m_Contents.resize( m_NLUTS );
00255     for (int i=0;i < m_NLUTS; i++) 
00256       m_Contents[i].resize( 1 << m_TotalInWidth );
00257 
00258       // switch to table mode
00259     m_UseLookupFunction = false;
00260   }  
00261   
00262   // continue to read contents (first line should be in buf)
00263   int maxrows = 1 << m_TotalInWidth;
00264   int row = 0;
00265   int current_index = -1;
00266   do {
00267     string line(buf);
00268     string::size_type i=0;
00269     if ( (i=line.find("//")) != string::npos) line.erase(i); // strip comments
00270     L1MuGMTLUTHelpers::Tokenizer tok("=", line);
00271 
00272     if (tok.size() == 2 && tok[0].find("CONTENTS") != string::npos) {
00273       L1MuGMTLUTHelpers::Tokenizer tok1("_",tok[0]);
00274       if (tok1.size() !=2) {
00275         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: error parsing contents tag " << tok[0] << ".";
00276         break;
00277       } 
00278 
00279       istringstream is(tok1[1].c_str());
00280       int newindex; 
00281       is >> newindex;
00282       if (newindex != current_index+1)
00283         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: warning: LUTS in LUT file are not in order.";
00284 
00285       if (newindex > m_NLUTS-1) {
00286         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: warning: LUT file contains LUT with too high index (" 
00287              << tok[0] 
00288              << "). max = " << m_NLUTS << " skipping.";
00289         newindex = -1;
00290       }
00291       current_index = newindex;
00292 
00293       if (row != 0) {
00294         if ( row < maxrows ) 
00295           edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: warning: LUT file only contains part of LUT contents.";
00296         row = 0;
00297       }
00298       istringstream is1(tok[1].c_str());
00299       unsigned value;
00300       if (is1 >> value) {
00301         if (current_index!=-1)
00302           Set (current_index, row++, value);    
00303       }
00304     }
00305     else {
00306       istringstream is1(line.c_str());
00307       unsigned value;
00308       if (is1 >> value) {
00309         if (row < maxrows) {
00310           if (current_index!=-1)
00311             Set (current_index, row++, value);  
00312         }
00313         else
00314           edm::LogWarning("LUTParsingProblem") 
00315                    << "L1MuGMTLUT::Load: warning: LUT file only contains LUT with too many entries. skipping.";
00316       }
00317     }
00318   } while ( in.getline(buf, sz) );
00319 }
00320 
00321 //--------------------------------------------------------------------------------
00322 // Generate a SubClass .h file
00323 //
00324 // to be used manually during code development
00325 
00326 void L1MuGMTLUT::MakeSubClass(const char* fname, const char* template_file_h, 
00327                               const char* template_file_cc) {
00328 
00329   // prepare parts
00330   string ins_name (m_name);
00331   string ins_name_upper = L1MuGMTLUTHelpers::upperCase (ins_name);
00332   string ins_instance_string;
00333   string ins_instances_enum;
00334   for (unsigned i=0; i<m_InstNames.size(); i++) {
00335     if (i!=0) ins_instance_string += ' ';
00336     ins_instance_string +=  m_InstNames[i];
00337 
00338     if (i!=0) ins_instances_enum += ", ";
00339     ins_instances_enum += m_InstNames[i];
00340   }
00341   char ins_vme[100]; 
00342   sprintf (ins_vme, "%d", m_vme_addr_width);
00343 
00344   char ins_distr_RAM[10];
00345   sprintf (ins_distr_RAM, "%s", m_distrRAM?"true":"false");
00346   
00347   
00348   string ins_input_decl_list, ins_input_list, ins_input_addr_list;
00349   for (unsigned i=0; i<m_Inputs.size(); i++) {
00350     ins_input_decl_list += string(", unsigned ") + m_Inputs[i].first;
00351     ins_input_list += string(", ") + m_Inputs[i].first;
00352     char tmp[100]; sprintf (tmp, " ,addr[%d]", i);
00353     ins_input_addr_list += string(tmp); 
00354   }
00355   
00356   //  string ins_lookup_functions;
00357   ostringstream os;
00358   for (unsigned i=0; i<m_Outputs.size(); i++) {
00359     os << "  /// specific lookup function for " <<  m_Outputs[i].first << endl;
00360     os << "  unsigned SpecificLookup_" << m_Outputs[i].first << " (int idx" << ins_input_decl_list << ") const {" << endl;
00361     os << "    vector<unsigned> addr(" << m_Inputs.size() << ");" << endl;
00362     for (unsigned j=0; j< m_Inputs.size(); j++) {
00363       os << "    addr[" << j << "] = " << m_Inputs[j].first << ";" << endl;
00364     }
00365     os << "    return Lookup(idx, addr) [" << i << "];" << endl;
00366     os << "  };" << endl << endl;
00367   }
00368   os << "  /// specific lookup function for entire output field" << endl;
00369   os << "  unsigned SpecificLookup (int idx" << ins_input_decl_list << ") const {" << endl;
00370   os << "    vector<unsigned> addr(" << m_Inputs.size() << ");" << endl;
00371   for (unsigned j=0; j< m_Inputs.size(); j++) {
00372     os << "    addr[" << j << "] = " << m_Inputs[j].first << ";" << endl;
00373   }
00374   os << "    return LookupPacked(idx, addr);" << endl;
00375   os << "  };" << endl << endl;
00376 
00377   os << ends;
00378   string ins_lookup_functions = os.str();
00379 
00380   // substitute in .h file
00381   string outfn (fname);
00382   if (outfn.size() == 0) outfn = string("../interface/L1MuGMT") +  m_name + string("LUT.h");
00383   ifstream of_check(outfn.c_str());
00384   if (! of_check.good() ) {
00385     ofstream of(outfn.c_str());
00386   
00387 
00388     ifstream in(template_file_h); 
00389     const int sz=1000; char buf[sz];
00390 
00391     while ( in.getline(buf, sz) ) {
00392       string line(buf);
00393 
00394       L1MuGMTLUTHelpers::replace(line, "###insert_name_upper###", ins_name_upper, false);
00395       L1MuGMTLUTHelpers::replace(line, "###insert_name###", ins_name, false); 
00396       L1MuGMTLUTHelpers::replace(line, "###insert_instance_string###", ins_instance_string, false);
00397       L1MuGMTLUTHelpers::replace(line, "###insert_instances_enum###", ins_instances_enum, false);
00398       L1MuGMTLUTHelpers::replace(line, "###insert_inputs_string###", string(PortDecoder(m_Inputs).str()), false);
00399       L1MuGMTLUTHelpers::replace(line, "###insert_outputs_string###", string(PortDecoder(m_Outputs).str()), false);
00400       L1MuGMTLUTHelpers::replace(line, "###insert_vme_input_width###", string(ins_vme), false);
00401       L1MuGMTLUTHelpers::replace(line, "###insert_distrRAM###", string(ins_distr_RAM), false);
00402       L1MuGMTLUTHelpers::replace(line, "###insert_input_decl_list###", ins_input_decl_list, false);
00403       L1MuGMTLUTHelpers::replace(line, "###insert_input_list###", ins_input_list, false);
00404       L1MuGMTLUTHelpers::replace(line, "###insert_input_addr_list###", ins_input_addr_list, false);
00405       L1MuGMTLUTHelpers::replace(line, "###insert_lookup_functions###", ins_lookup_functions, false);
00406       of << line << endl;
00407     }    
00408   }
00409 
00410   // substitute in .cc file
00411   string outfn_cc (fname);
00412   if (outfn_cc.size() == 0) outfn_cc = string("../interface/L1MuGMT") +  m_name + string("LUT.cc");
00413 
00414   ifstream of_cc_check( outfn_cc.c_str() );
00415   if (! of_cc_check.good() ) {
00416     ofstream of_cc(outfn_cc.c_str());
00417   
00418 
00419     ifstream in_cc(template_file_cc); 
00420     const int sz=1000; char buf[sz];
00421 
00422     while ( in_cc.getline(buf, sz) ) {
00423       string line(buf);
00424 
00425       L1MuGMTLUTHelpers::replace(line, "###insert_name_upper###", ins_name_upper, false);
00426       L1MuGMTLUTHelpers::replace(line, "###insert_name###", ins_name, false); 
00427       L1MuGMTLUTHelpers::replace(line, "###insert_instance_string###", ins_instance_string, false);
00428       L1MuGMTLUTHelpers::replace(line, "###insert_instances_enum###", ins_instances_enum, false);
00429       L1MuGMTLUTHelpers::replace(line, "###insert_inputs_string###", string(PortDecoder(m_Inputs).str()), false);
00430       L1MuGMTLUTHelpers::replace(line, "###insert_outputs_string###", string(PortDecoder(m_Outputs).str()), false);
00431       L1MuGMTLUTHelpers::replace(line, "###insert_vme_input_width###", string(ins_vme), false);
00432       L1MuGMTLUTHelpers::replace(line, "###insert_distrRAM###", string(ins_distr_RAM), false);
00433       L1MuGMTLUTHelpers::replace(line, "###insert_input_decl_list###", ins_input_decl_list, false);
00434       L1MuGMTLUTHelpers::replace(line, "###insert_input_list###", ins_input_list, false);
00435       L1MuGMTLUTHelpers::replace(line, "###insert_input_addr_list###", ins_input_addr_list, false);
00436       L1MuGMTLUTHelpers::replace(line, "###insert_lookup_functions###", ins_lookup_functions, false);
00437       of_cc << line << endl;
00438     }    
00439   }
00440 }
00441 
00442