Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:19:57

0001 //-------------------------------------------------
0002 //
0003 //   \class L1MuGMTLUT
0004 /**
0005  *   A general-purpose Look-Up-Table Class
0006  *   Base class for all LUTs in the GMT
0007  * 
0008 */
0009 //
0010 //
0011 //   Author :
0012 //   H. Sakulin            HEPHY Vienna
0013 //
0014 //   Migrated to CMSSW:
0015 //   I. Mikulec
0016 //
0017 //--------------------------------------------------
0018 
0019 //---------------
0020 // C++ Headers --
0021 //---------------
0022 
0023 #include <L1Trigger/GlobalMuonTrigger/src/L1MuGMTLUT.h>
0024 #include <boost/algorithm/string.hpp>
0025 #include <iostream>
0026 #include <fstream>
0027 #include <sstream>
0028 
0029 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0030 
0031 #include "L1Trigger/GlobalMuonTrigger/src/L1MuGMTConfig.h"
0032 
0033 using namespace std;
0034 
0035 L1MuGMTLUT::~L1MuGMTLUT() {
0036   if (!m_UseLookupFunction) {
0037     // de-allocate vectors
0038     // no destuction needed for vector< vector <unsigned> >
0039 
0040     // for (int i=0;i < m_NLUTS; i++)
0041     //   m_Contents[i].clear();
0042     // m_Contents.clear();
0043   }
0044 }
0045 
0046 void L1MuGMTLUT::Init(const char* name,
0047                       const vector<string>& instances,
0048                       const vector<port>& in_widths,
0049                       const vector<port>& out_widths,
0050                       unsigned vme_addr_width,
0051                       bool distrRAM) {
0052   m_name = name;
0053   m_InstNames = instances;
0054   m_NLUTS = instances.size();
0055 
0056   m_Inputs = in_widths;
0057   m_TotalInWidth = 0;
0058   for (unsigned i = 0; i < in_widths.size(); i++)
0059     m_TotalInWidth += in_widths[i].second;
0060 
0061   m_Outputs = out_widths;
0062   m_TotalOutWidth = 0;
0063   for (unsigned i = 0; i < out_widths.size(); i++)
0064     m_TotalOutWidth += out_widths[i].second;
0065 
0066   m_vme_addr_width = vme_addr_width;
0067   m_distrRAM = distrRAM;
0068 
0069   if (m_distrRAM && (m_TotalInWidth != vme_addr_width)) {
0070     edm::LogWarning("AddressMismatch") << "L1MuGMTLUT::Init(): for distributed RAM the GMT (Input) address width "
0071                                        << "has to match the VME address width. Core Generation will not work.";
0072   }
0073 
0074   m_GeneralLUTVersion = L1MuGMTConfig::getVersionLUTs();
0075   m_initialized = true;
0076 }
0077 
0078 void L1MuGMTLUT::Save(const char* path) {
0079   if (!m_initialized) {
0080     edm::LogWarning("LUTNotInitialized") << "L1MuGMTLUT::Save: LUT not initialized. ";
0081     return;
0082   }
0083 
0084   m_saveFlag = true;
0085 
0086   ofstream of(path);
0087   of << "// This is a CMS L1 Global Muon Trigger .lut file. " << endl;
0088   of << "//  " << endl;
0089   of << "// It defines a set of look-up-tables(LUTs) of the same type (same inputs and outputs) but" << endl;
0090   of << "// with different default contents. For example a certain type of LUT can have different" << endl;
0091   of << "// default values for DT for RPC and for CSC muons. " << endl;
0092   of << "//  " << endl;
0093   of << "// NAME           gives the name of the LUT. It should match the base name (name without '.lut')" << endl;
0094   of << "//                of the LUT file." << endl;
0095   of << "//                When deriving a C++ sub-class the name is used case sensitive." << endl;
0096   of << "//                In generated VHDL code the name is used in lower case." << endl;
0097   of << "//  " << endl;
0098   of << "// INSTANCES      is the list of instances of the LUT with different default values." << endl;
0099   of << "//                the lists consists of identifiers for each of the instances separated by spaces." << endl;
0100   of << "//                the identifiers can be made up of characters that are valid in VHDL lables. " << endl;
0101   of << "//                In the VHDL code they are used to label the different instances." << endl;
0102   of << "//  " << endl;
0103   of << "//                In C++ and VHDL the instance of a LUT is selected by an integer index where 0 " << endl;
0104   of << "//                corresponds to the leftmost identifier. Integer indices are also used in the CONTENTS_XX"
0105      << endl;
0106   of << "//                statements in this file." << endl;
0107   of << "//  " << endl;
0108   of << "// LUT_INPUTS     is the (space-separated) list of inputs of the LUT. Each input is specified in the form"
0109      << endl;
0110   of << "//                <input_name>(<number_of_bits>) where <input_name> is the name of the input and" << endl;
0111   of << "//                <number_of_bits> is the number of bits of the input. <input_name> has to be a valid" << endl;
0112   of << "//                identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
0113   of << "//  " << endl;
0114   of << "//                All LUT inputs together make up the address of the corresponding memory." << endl;
0115   of << "//                The first input in the list corresponds to the most-significant bits of the address."
0116      << endl;
0117   of << "//  " << endl;
0118   of << "// LUT_OUTPUTS    is the (space-separated) list of outputs of the LUT. Each output is specified in the form"
0119      << endl;
0120   of << "//                <output_name>(<number_of_bits>) where <output_name> is the name of the output and" << endl;
0121   of << "//                <number_of_bits> is the number of bits of the output. <output_name> has to be a valid"
0122      << endl;
0123   of << "//                identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
0124   of << "//  " << endl;
0125   of << "//                All LUT outputs together make up the data of the corresponding memory." << endl;
0126   of << "//                The first output in the list corresponds to the most-significant data bits." << endl;
0127   of << "//  " << endl;
0128   of << "// VME_ADDR_WIDTH is the address width of the LUT memory when accessed via VME. When the LUT " << endl;
0129   of << "//                is implemented as dual-port block RAM, the VME address with can be different " << endl;
0130   of << "//                from the address width given by the sum of the input widths. It can be larger or" << endl;
0131   of << "//                smaller by a factor of 2^n. When the LUT is implemented as dual-port distributed RAM,"
0132      << endl;
0133   of << "//                the VME address width has to match the input width. " << endl;
0134   of << "//  " << endl;
0135   of << "// DISTRIBUTED_RAM is 1 if the LUT is to be implemented in distributed RAM and 0 for Block RAM " << endl;
0136   of << "//                 Note that for distributed RAM the address width on the GMT side (sum of input widths)"
0137      << endl;
0138   of << "//                 has to match the vme_addr_width" << endl;
0139   of << "//  " << endl;
0140   of << "// CONTENTS_XX    specifies the default contents of instance with index XX (see INSTANCES)." << endl;
0141   of << "//                contents are specified as decimal numbers, one number per line." << endl;
0142   of << "//  " << endl;
0143   of << "// Hannes Sakulin / HEPHY Vienna, 2003" << endl;
0144   of << "// " << endl;
0145 
0146   of << "NAME = " << m_name << endl;
0147   of << "INSTANCES =";
0148   for (unsigned i = 0; i < m_InstNames.size(); i++)
0149     of << " " << m_InstNames[i];
0150   of << endl;
0151   of << "LUT_INPUTS = " << PortDecoder(m_Inputs).str() << endl;
0152   of << "LUT_OUTPUTS = " << PortDecoder(m_Outputs).str() << endl;
0153   of << "VME_ADDR_WIDTH = " << m_vme_addr_width << endl;
0154   of << "DISTRIBUTED_RAM = " << (m_distrRAM ? "1" : "0") << endl;
0155   for (int i = 0; i < m_NLUTS; i++) {
0156     of << "// " << m_InstNames[i] << endl;
0157     of << "CONTENTS_" << i << " = ";
0158     for (unsigned addr = 0; addr < (unsigned)(1 << m_TotalInWidth); addr++) {
0159       of << LookupPacked(i, addr) << endl;
0160     }
0161     of << endl;
0162   }
0163 
0164   m_saveFlag = false;
0165 }
0166 
0167 // Rules for file
0168 //
0169 // NAME = VALUE1 [VALUE2 [...]]
0170 // All header variables have to be set before first contents variable
0171 // comments start with "//" and go up to end of line
0172 //
0173 // when writing back, comments will be save first
0174 
0175 //--------------------------------------------------------------------------------
0176 
0177 void L1MuGMTLUT::Set(int idx, unsigned address, unsigned value) {
0178   if (!m_initialized) {
0179     edm::LogWarning("LUTNotInitialized") << "L1MuGMTLUT::Set: LUT not initialized. ";
0180     return;
0181   }
0182 
0183   if (idx >= m_NLUTS) {
0184     edm::LogWarning("LUTRangeViolation") << "L1MuGMTLUT::Set: LUT index exceeds range (0 to " << (m_NLUTS - 1) << ").";
0185     return;
0186   }
0187   if (address >= (unsigned)(1 << m_TotalInWidth)) {
0188     edm::LogWarning("LUTRangeViolation") << "Error in L1MuGMTLUT::Set: LUT input exceeds range (0 to "
0189                                          << ((1 << m_TotalInWidth) - 1) << ").";
0190     return;
0191   }
0192   if (value >= (unsigned)(1 << m_TotalOutWidth)) {
0193     edm::LogWarning("LUTRangeViolation") << "Error in L1MuGMTLUT::Set: LUT output exceeds range (0 to "
0194                                          << ((1 << m_TotalOutWidth) - 1) << ").";
0195     return;
0196   }
0197   m_Contents[idx][address] = value;
0198 }
0199 
0200 void L1MuGMTLUT::Load(const char* path) {
0201   string lf_name("");
0202   vector<string> lf_InstNames;
0203   vector<port> lf_Inputs;
0204   vector<port> lf_Outputs;
0205   unsigned lf_vme_addr_width = 0;
0206   bool lf_distrRAM = false;
0207   vector<string> lf_comments;
0208 
0209   ifstream in(path);
0210   const int sz = 1000;
0211   char buf[sz];
0212 
0213   // read header
0214 
0215   while (in.getline(buf, sz)) {
0216     string line(buf);
0217     string::size_type i = 0;
0218     if ((i = line.find("//")) != string::npos) {
0219       lf_comments.push_back(line.substr(i));  // save comments
0220       line.erase(i);                          // and strip
0221     }
0222     L1MuGMTLUTHelpers::Tokenizer tok("=", line);
0223     if (tok.size() == 2) {
0224       L1MuGMTLUTHelpers::replace(tok[0], " ", "", false);   // skip spaces
0225       L1MuGMTLUTHelpers::replace(tok[0], "\t", "", false);  // skip tabs
0226 
0227       L1MuGMTLUTHelpers::replace(tok[1], "\t", " ", false);  // convert tabs to spaces
0228       L1MuGMTLUTHelpers::replace(tok[1], "  ", " ", true);   // skip multiple spaces
0229       tok[1].erase(0, tok[1].find_first_not_of(' '));        // skip leading spaces
0230       tok[1].erase(tok[1].find_last_not_of(' ') + 1);        // skip trailing spaces
0231 
0232       if (tok[0] == "NAME")
0233         lf_name = tok[1];
0234       else if (tok[0] == "INSTANCES") {
0235         lf_InstNames = L1MuGMTLUTHelpers::Tokenizer(" ", tok[1]);
0236       } else if (tok[0] == "LUT_INPUTS")
0237         lf_Inputs = PortDecoder(tok[1]);
0238       else if (tok[0] == "LUT_OUTPUTS")
0239         lf_Outputs = PortDecoder(tok[1]);
0240       else if (tok[0] == "VME_ADDR_WIDTH")
0241         lf_vme_addr_width = atoi(tok[1].c_str());
0242       else if (tok[0] == "DISTRIBUTED_RAM")
0243         lf_distrRAM = (atoi(tok[1].c_str()) == 1);
0244     }
0245     if (tok[0].find("CONTENTS") != string::npos)
0246       break;
0247   }
0248 
0249   if (!m_initialized) {  // then initialize
0250     Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
0251   } else {  // verify compatibility
0252     if (m_name != lf_name || m_InstNames != lf_InstNames || m_Inputs != lf_Inputs || m_Outputs != lf_Outputs ||
0253         m_vme_addr_width != lf_vme_addr_width || m_distrRAM != lf_distrRAM) {
0254       edm::LogWarning("LUTParmasMismatch")
0255           << "L1MuGMTLUT::Load: error: parameters in file do not match configuration of LUT. Load failed.";
0256       return;
0257     }
0258   }
0259 
0260   if (m_UseLookupFunction) {
0261     // allocate vectors
0262     m_Contents.resize(m_NLUTS);
0263     for (int i = 0; i < m_NLUTS; i++)
0264       m_Contents[i].resize(1 << m_TotalInWidth);
0265 
0266     // switch to table mode
0267     m_UseLookupFunction = false;
0268   }
0269 
0270   // continue to read contents (first line should be in buf)
0271   int maxrows = 1 << m_TotalInWidth;
0272   int row = 0;
0273   int current_index = -1;
0274   do {
0275     string line(buf);
0276     string::size_type i = 0;
0277     if ((i = line.find("//")) != string::npos)
0278       line.erase(i);  // strip comments
0279     L1MuGMTLUTHelpers::Tokenizer tok("=", line);
0280 
0281     if (tok.size() == 2 && tok[0].find("CONTENTS") != string::npos) {
0282       L1MuGMTLUTHelpers::Tokenizer tok1("_", tok[0]);
0283       if (tok1.size() != 2) {
0284         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: error parsing contents tag " << tok[0] << ".";
0285         break;
0286       }
0287 
0288       istringstream is(tok1[1]);
0289       int newindex;
0290       is >> newindex;
0291       if (newindex != current_index + 1)
0292         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: warning: LUTS in LUT file are not in order.";
0293 
0294       if (newindex > m_NLUTS - 1) {
0295         edm::LogWarning("LUTParsingProblem") << "L1MuGMTLUT::Load: warning: LUT file contains LUT with too high index ("
0296                                              << tok[0] << "). max = " << m_NLUTS << " skipping.";
0297         newindex = -1;
0298       }
0299       current_index = newindex;
0300 
0301       if (row != 0) {
0302         if (row < maxrows)
0303           edm::LogWarning("LUTParsingProblem")
0304               << "L1MuGMTLUT::Load: warning: LUT file only contains part of LUT contents.";
0305         row = 0;
0306       }
0307       istringstream is1(tok[1]);
0308       unsigned value;
0309       if (is1 >> value) {
0310         if (current_index != -1)
0311           Set(current_index, row++, value);
0312       }
0313     } else {
0314       istringstream is1(line);
0315       unsigned value;
0316       if (is1 >> value) {
0317         if (row < maxrows) {
0318           if (current_index != -1)
0319             Set(current_index, row++, value);
0320         } else
0321           edm::LogWarning("LUTParsingProblem")
0322               << "L1MuGMTLUT::Load: warning: LUT file only contains LUT with too many entries. skipping.";
0323       }
0324     }
0325   } while (in.getline(buf, sz));
0326 }
0327 
0328 //--------------------------------------------------------------------------------
0329 // Generate a SubClass .h file
0330 //
0331 // to be used manually during code development
0332 
0333 void L1MuGMTLUT::MakeSubClass(const char* fname, const char* template_file_h, const char* template_file_cc) {
0334   // prepare parts
0335   string ins_name(m_name);
0336   string ins_name_upper = boost::to_upper_copy(ins_name);
0337   string ins_instance_string;
0338   string ins_instances_enum;
0339   for (unsigned i = 0; i < m_InstNames.size(); i++) {
0340     if (i != 0)
0341       ins_instance_string += ' ';
0342     ins_instance_string += m_InstNames[i];
0343 
0344     if (i != 0)
0345       ins_instances_enum += ", ";
0346     ins_instances_enum += m_InstNames[i];
0347   }
0348   char ins_vme[100];
0349   sprintf(ins_vme, "%d", m_vme_addr_width);
0350 
0351   char ins_distr_RAM[10];
0352   sprintf(ins_distr_RAM, "%s", m_distrRAM ? "true" : "false");
0353 
0354   string ins_input_decl_list, ins_input_list, ins_input_addr_list;
0355   for (unsigned i = 0; i < m_Inputs.size(); i++) {
0356     ins_input_decl_list += string(", unsigned ") + m_Inputs[i].first;
0357     ins_input_list += string(", ") + m_Inputs[i].first;
0358     char tmp[100];
0359     sprintf(tmp, " ,addr[%d]", i);
0360     ins_input_addr_list += string(tmp);
0361   }
0362 
0363   //  string ins_lookup_functions;
0364   ostringstream os;
0365   for (unsigned i = 0; i < m_Outputs.size(); i++) {
0366     os << "  /// specific lookup function for " << m_Outputs[i].first << endl;
0367     os << "  unsigned SpecificLookup_" << m_Outputs[i].first << " (int idx" << ins_input_decl_list << ") const {"
0368        << endl;
0369     os << "    vector<unsigned> addr(" << m_Inputs.size() << ");" << endl;
0370     for (unsigned j = 0; j < m_Inputs.size(); j++) {
0371       os << "    addr[" << j << "] = " << m_Inputs[j].first << ";" << endl;
0372     }
0373     os << "    return Lookup(idx, addr) [" << i << "];" << endl;
0374     os << "  };" << endl << endl;
0375   }
0376   os << "  /// specific lookup function for entire output field" << endl;
0377   os << "  unsigned SpecificLookup (int idx" << ins_input_decl_list << ") const {" << endl;
0378   os << "    vector<unsigned> addr(" << m_Inputs.size() << ");" << endl;
0379   for (unsigned j = 0; j < m_Inputs.size(); j++) {
0380     os << "    addr[" << j << "] = " << m_Inputs[j].first << ";" << endl;
0381   }
0382   os << "    return LookupPacked(idx, addr);" << endl;
0383   os << "  };" << endl << endl;
0384 
0385   os << ends;
0386   string ins_lookup_functions = os.str();
0387 
0388   // substitute in .h file
0389   string outfn(fname);
0390   if (outfn.empty())
0391     outfn = string("../interface/L1MuGMT") + m_name + string("LUT.h");
0392   ifstream of_check(outfn.c_str());
0393   if (!of_check.good()) {
0394     ofstream of(outfn.c_str());
0395 
0396     ifstream in(template_file_h);
0397     const int sz = 1000;
0398     char buf[sz];
0399 
0400     while (in.getline(buf, sz)) {
0401       string line(buf);
0402 
0403       L1MuGMTLUTHelpers::replace(line, "###insert_name_upper###", ins_name_upper, false);
0404       L1MuGMTLUTHelpers::replace(line, "###insert_name###", ins_name, false);
0405       L1MuGMTLUTHelpers::replace(line, "###insert_instance_string###", ins_instance_string, false);
0406       L1MuGMTLUTHelpers::replace(line, "###insert_instances_enum###", ins_instances_enum, false);
0407       L1MuGMTLUTHelpers::replace(line, "###insert_inputs_string###", string(PortDecoder(m_Inputs).str()), false);
0408       L1MuGMTLUTHelpers::replace(line, "###insert_outputs_string###", string(PortDecoder(m_Outputs).str()), false);
0409       L1MuGMTLUTHelpers::replace(line, "###insert_vme_input_width###", string(ins_vme), false);
0410       L1MuGMTLUTHelpers::replace(line, "###insert_distrRAM###", string(ins_distr_RAM), false);
0411       L1MuGMTLUTHelpers::replace(line, "###insert_input_decl_list###", ins_input_decl_list, false);
0412       L1MuGMTLUTHelpers::replace(line, "###insert_input_list###", ins_input_list, false);
0413       L1MuGMTLUTHelpers::replace(line, "###insert_input_addr_list###", ins_input_addr_list, false);
0414       L1MuGMTLUTHelpers::replace(line, "###insert_lookup_functions###", ins_lookup_functions, false);
0415       of << line << endl;
0416     }
0417   }
0418 
0419   // substitute in .cc file
0420   string outfn_cc(fname);
0421   if (outfn_cc.empty())
0422     outfn_cc = string("../interface/L1MuGMT") + m_name + string("LUT.cc");
0423 
0424   ifstream of_cc_check(outfn_cc.c_str());
0425   if (!of_cc_check.good()) {
0426     ofstream of_cc(outfn_cc.c_str());
0427 
0428     ifstream in_cc(template_file_cc);
0429     const int sz = 1000;
0430     char buf[sz];
0431 
0432     while (in_cc.getline(buf, sz)) {
0433       string line(buf);
0434 
0435       L1MuGMTLUTHelpers::replace(line, "###insert_name_upper###", ins_name_upper, false);
0436       L1MuGMTLUTHelpers::replace(line, "###insert_name###", ins_name, false);
0437       L1MuGMTLUTHelpers::replace(line, "###insert_instance_string###", ins_instance_string, false);
0438       L1MuGMTLUTHelpers::replace(line, "###insert_instances_enum###", ins_instances_enum, false);
0439       L1MuGMTLUTHelpers::replace(line, "###insert_inputs_string###", string(PortDecoder(m_Inputs).str()), false);
0440       L1MuGMTLUTHelpers::replace(line, "###insert_outputs_string###", string(PortDecoder(m_Outputs).str()), false);
0441       L1MuGMTLUTHelpers::replace(line, "###insert_vme_input_width###", string(ins_vme), false);
0442       L1MuGMTLUTHelpers::replace(line, "###insert_distrRAM###", string(ins_distr_RAM), false);
0443       L1MuGMTLUTHelpers::replace(line, "###insert_input_decl_list###", ins_input_decl_list, false);
0444       L1MuGMTLUTHelpers::replace(line, "###insert_input_list###", ins_input_list, false);
0445       L1MuGMTLUTHelpers::replace(line, "###insert_input_addr_list###", ins_input_addr_list, false);
0446       L1MuGMTLUTHelpers::replace(line, "###insert_lookup_functions###", ins_lookup_functions, false);
0447       of_cc << line << endl;
0448     }
0449   }
0450 }