00001
00002
00003
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00041
00042
00043
00044
00045
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
00163
00164
00165
00166
00167
00168
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
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) );
00216 line.erase(i);
00217 }
00218 L1MuGMTLUTHelpers::Tokenizer tok("=", line);
00219 if (tok.size() == 2) {
00220 L1MuGMTLUTHelpers::replace(tok[0], " ","", false);
00221 L1MuGMTLUTHelpers::replace(tok[0], "\t","", false);
00222
00223 L1MuGMTLUTHelpers::replace(tok[1], "\t", " ", false);
00224 L1MuGMTLUTHelpers::replace(tok[1], " ", " ", true);
00225 tok[1].erase(0, tok[1].find_first_not_of(" "));
00226 tok[1].erase(tok[1].find_last_not_of(" ")+1);
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) {
00239 Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
00240 }
00241 else {
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
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
00261 m_UseLookupFunction = false;
00262 }
00263
00264
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);
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
00325
00326
00327
00328 void L1MuGMTLUT::MakeSubClass(const char* fname, const char* template_file_h,
00329 const char* template_file_cc) {
00330
00331
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
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
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
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