CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/L1Trigger/GlobalMuonTrigger/src/L1MuGMTLUT.cc

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