24 #include <boost/algorithm/string.hpp> 36 if (! m_UseLookupFunction ) {
48 const vector<port>& in_widths,
const vector<port>& out_widths,
49 unsigned vme_addr_width,
bool distrRAM)
52 m_InstNames = instances;
53 m_NLUTS = instances.size();
57 for (
unsigned i=0;
i< in_widths.size();
i++) m_TotalInWidth += in_widths[
i].
second;
59 m_Outputs = out_widths;
61 for (
unsigned i=0;
i< out_widths.size();
i++) m_TotalOutWidth += out_widths[
i].
second;
63 m_vme_addr_width = vme_addr_width;
64 m_distrRAM = distrRAM;
66 if (m_distrRAM && (m_TotalInWidth != vme_addr_width) ) {
68 <<
"L1MuGMTLUT::Init(): for distributed RAM the GMT (Input) address width " 69 <<
"has to match the VME address width. Core Generation will not work.";
78 if (! m_initialized) {
79 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Save: LUT not initialized. ";
86 of <<
"// This is a CMS L1 Global Muon Trigger .lut file. " << endl;
88 of <<
"// It defines a set of look-up-tables(LUTs) of the same type (same inputs and outputs) but" << endl;
89 of <<
"// with different default contents. For example a certain type of LUT can have different" << endl;
90 of <<
"// default values for DT for RPC and for CSC muons. " << endl;
92 of <<
"// NAME gives the name of the LUT. It should match the base name (name without '.lut')" << endl;
93 of <<
"// of the LUT file." << endl;
94 of <<
"// When deriving a C++ sub-class the name is used case sensitive." << endl;
95 of <<
"// In generated VHDL code the name is used in lower case." << endl;
97 of <<
"// INSTANCES is the list of instances of the LUT with different default values." << endl;
98 of <<
"// the lists consists of identifiers for each of the instances separated by spaces." << endl;
99 of <<
"// the identifiers can be made up of characters that are valid in VHDL lables. " << endl;
100 of <<
"// In the VHDL code they are used to label the different instances." << endl;
102 of <<
"// In C++ and VHDL the instance of a LUT is selected by an integer index where 0 " << endl;
103 of <<
"// corresponds to the leftmost identifier. Integer indices are also used in the CONTENTS_XX" << endl;
104 of <<
"// statements in this file." << endl;
106 of <<
"// LUT_INPUTS is the (space-separated) list of inputs of the LUT. Each input is specified in the form" << endl;
107 of <<
"// <input_name>(<number_of_bits>) where <input_name> is the name of the input and" << endl;
108 of <<
"// <number_of_bits> is the number of bits of the input. <input_name> has to be a valid" << endl;
109 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
111 of <<
"// All LUT inputs together make up the address of the corresponding memory." << endl;
112 of <<
"// The first input in the list corresponds to the most-significant bits of the address." << endl;
114 of <<
"// LUT_OUTPUTS is the (space-separated) list of outputs of the LUT. Each output is specified in the form" << endl;
115 of <<
"// <output_name>(<number_of_bits>) where <output_name> is the name of the output and" << endl;
116 of <<
"// <number_of_bits> is the number of bits of the output. <output_name> has to be a valid" << endl;
117 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
119 of <<
"// All LUT outputs together make up the data of the corresponding memory." << endl;
120 of <<
"// The first output in the list corresponds to the most-significant data bits." << endl;
122 of <<
"// VME_ADDR_WIDTH is the address width of the LUT memory when accessed via VME. When the LUT " << endl;
123 of <<
"// is implemented as dual-port block RAM, the VME address with can be different " << endl;
124 of <<
"// from the address width given by the sum of the input widths. It can be larger or" << endl;
125 of <<
"// smaller by a factor of 2^n. When the LUT is implemented as dual-port distributed RAM," << endl;
126 of <<
"// the VME address width has to match the input width. " << endl;
128 of <<
"// DISTRIBUTED_RAM is 1 if the LUT is to be implemented in distributed RAM and 0 for Block RAM " << endl;
129 of <<
"// Note that for distributed RAM the address width on the GMT side (sum of input widths)" << endl;
130 of <<
"// has to match the vme_addr_width" << endl;
132 of <<
"// CONTENTS_XX specifies the default contents of instance with index XX (see INSTANCES)." << endl;
133 of <<
"// contents are specified as decimal numbers, one number per line." << endl;
135 of <<
"// Hannes Sakulin / HEPHY Vienna, 2003" << endl;
138 of <<
"NAME = " << m_name << endl;
139 of <<
"INSTANCES =" ;
140 for (
unsigned i=0;
i<m_InstNames.size();
i++) of <<
" " << m_InstNames[
i];
144 of <<
"VME_ADDR_WIDTH = " << m_vme_addr_width << endl;
145 of <<
"DISTRIBUTED_RAM = " << (m_distrRAM?
"1":
"0") << endl;
146 for (
int i=0;
i<m_NLUTS;
i++) {
147 of <<
"// " << m_InstNames[
i] << endl;
148 of <<
"CONTENTS_" <<
i <<
" = ";
149 for (
unsigned addr = 0; addr < (unsigned) (1<<m_TotalInWidth); addr ++) {
150 of << LookupPacked (i, addr) << endl;
172 if (! m_initialized) {
173 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Set: LUT not initialized. ";
177 if ( idx >= m_NLUTS ) {
178 edm::LogWarning(
"LUTRangeViolation") <<
"L1MuGMTLUT::Set: LUT index exceeds range (0 to " << ( m_NLUTS -1 ) <<
").";
181 if ( address >= (
unsigned)(1 << m_TotalInWidth) ) {
182 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT input exceeds range (0 to " << ( (1 << m_TotalInWidth) -1 ) <<
").";
185 if ( value >= (
unsigned)(1 << m_TotalOutWidth) ) {
186 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT output exceeds range (0 to " << ( (1 << m_TotalOutWidth) -1 ) <<
")." ;
196 vector <string> lf_InstNames;
197 vector <port> lf_Inputs;
198 vector <port> lf_Outputs;
199 unsigned lf_vme_addr_width=0;
200 bool lf_distrRAM=
false;
201 vector<string> lf_comments;
204 const int sz=1000;
char buf[sz];
209 while ( in.getline(buf, sz) ) {
212 if ( (i=line.find(
"//")) != string::npos) {
213 lf_comments.push_back( line.substr(i) );
217 if (tok.size() == 2) {
223 tok[1].erase(0, tok[1].find_first_not_of(
" "));
224 tok[1].erase(tok[1].find_last_not_of(
" ")+1);
226 if (tok[0] ==
"NAME") lf_name = tok[1];
228 else if (tok[0] ==
"LUT_INPUTS") lf_Inputs =
PortDecoder(tok[1]);
229 else if (tok[0] ==
"LUT_OUTPUTS") lf_Outputs =
PortDecoder(tok[1]);
230 else if (tok[0] ==
"VME_ADDR_WIDTH") lf_vme_addr_width = atoi(tok[1].c_str());
231 else if (tok[0] ==
"DISTRIBUTED_RAM") lf_distrRAM = ( atoi(tok[1].c_str()) == 1 );
233 if (tok[0].
find(
"CONTENTS") != string::npos)
break;
236 if (!m_initialized) {
237 Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
240 if (m_name != lf_name ||
241 m_InstNames != lf_InstNames ||
242 m_Inputs != lf_Inputs ||
243 m_Outputs != lf_Outputs ||
244 m_vme_addr_width != lf_vme_addr_width ||
245 m_distrRAM != lf_distrRAM) {
247 <<
"L1MuGMTLUT::Load: error: parameters in file do not match configuration of LUT. Load failed.";
252 if (m_UseLookupFunction) {
254 m_Contents.resize( m_NLUTS );
255 for (
int i=0;
i < m_NLUTS;
i++)
256 m_Contents[
i].resize( 1 << m_TotalInWidth );
259 m_UseLookupFunction =
false;
263 int maxrows = 1 << m_TotalInWidth;
265 int current_index = -1;
269 if ( (i=line.find(
"//")) != string::npos) line.erase(i);
272 if (tok.size() == 2 && tok[0].find(
"CONTENTS") != string::npos) {
274 if (tok1.size() !=2) {
275 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: error parsing contents tag " << tok[0] <<
".";
279 istringstream is(tok1[1].c_str());
282 if (newindex != current_index+1)
283 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUTS in LUT file are not in order.";
285 if (newindex > m_NLUTS-1) {
286 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUT file contains LUT with too high index (" 288 <<
"). max = " << m_NLUTS <<
" skipping.";
291 current_index = newindex;
295 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUT file only contains part of LUT contents.";
298 istringstream is1(tok[1].c_str());
301 if (current_index!=-1)
302 Set (current_index, row++, value);
306 istringstream is1(line.c_str());
310 if (current_index!=-1)
311 Set (current_index, row++, value);
315 <<
"L1MuGMTLUT::Load: warning: LUT file only contains LUT with too many entries. skipping.";
318 }
while ( in.getline(buf, sz) );
327 const char* template_file_cc) {
330 string ins_name (m_name);
331 string ins_name_upper = boost::to_upper_copy(ins_name);
332 string ins_instance_string;
333 string ins_instances_enum;
334 for (
unsigned i=0;
i<m_InstNames.size();
i++) {
335 if (
i!=0) ins_instance_string +=
' ';
336 ins_instance_string += m_InstNames[
i];
338 if (
i!=0) ins_instances_enum +=
", ";
339 ins_instances_enum += m_InstNames[
i];
342 sprintf (ins_vme,
"%d", m_vme_addr_width);
344 char ins_distr_RAM[10];
345 sprintf (ins_distr_RAM,
"%s", m_distrRAM?
"true":
"false");
348 string ins_input_decl_list, ins_input_list, ins_input_addr_list;
349 for (
unsigned i=0;
i<m_Inputs.size();
i++) {
350 ins_input_decl_list +=
string(
", unsigned ") + m_Inputs[
i].first;
351 ins_input_list +=
string(
", ") + m_Inputs[
i].first;
352 char tmp[100]; sprintf (tmp,
" ,addr[%d]",
i);
353 ins_input_addr_list +=
string(tmp);
358 for (
unsigned i=0;
i<m_Outputs.size();
i++) {
359 os <<
" /// specific lookup function for " << m_Outputs[
i].first << endl;
360 os <<
" unsigned SpecificLookup_" << m_Outputs[
i].first <<
" (int idx" << ins_input_decl_list <<
") const {" << endl;
361 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
362 for (
unsigned j=0; j< m_Inputs.size(); j++) {
363 os <<
" addr[" << j <<
"] = " << m_Inputs[j].first <<
";" << endl;
365 os <<
" return Lookup(idx, addr) [" <<
i <<
"];" << endl;
366 os <<
" };" << endl << endl;
368 os <<
" /// specific lookup function for entire output field" << endl;
369 os <<
" unsigned SpecificLookup (int idx" << ins_input_decl_list <<
") const {" << endl;
370 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
371 for (
unsigned j=0; j< m_Inputs.size(); j++) {
372 os <<
" addr[" << j <<
"] = " << m_Inputs[j].first <<
";" << endl;
374 os <<
" return LookupPacked(idx, addr);" << endl;
375 os <<
" };" << endl << endl;
378 string ins_lookup_functions = os.str();
381 string outfn (fname);
382 if (outfn.size() == 0) outfn =
string(
"../interface/L1MuGMT") + m_name +
string(
"LUT.h");
383 ifstream of_check(outfn.c_str());
384 if (! of_check.good() ) {
385 ofstream of(outfn.c_str());
388 ifstream
in(template_file_h);
389 const int sz=1000;
char buf[sz];
391 while ( in.getline(buf, sz) ) {
411 string outfn_cc (fname);
412 if (outfn_cc.size() == 0) outfn_cc =
string(
"../interface/L1MuGMT") + m_name +
string(
"LUT.cc");
414 ifstream of_cc_check( outfn_cc.c_str() );
415 if (! of_cc_check.good() ) {
416 ofstream of_cc(outfn_cc.c_str());
419 ifstream in_cc(template_file_cc);
420 const int sz=1000;
char buf[sz];
422 while ( in_cc.getline(buf, sz) ) {
437 of_cc << line << endl;
virtual ~L1MuGMTLUT()
destructor
void Set(int idx, unsigned address, unsigned value)
set with single address and value
void MakeSubClass(const char *fname="", const char *template_file_h="../interface/L1MuGMTLUT_SubClass.h_template", const char *template_file_cc="../interface/L1MuGMTLUT_SubClass.cc_template")
Add Generate SubClass method.
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
U second(std::pair< T, U > const &p)
static unsigned getVersionLUTs()
void Save(const char *path)
save to LUT file
void Load(const char *path)
I/O functions.
std::vector< std::vector< double > > tmp
static int replace(std::string &input, const std::string &gone, const std::string &it, bool multiple)
void Init(const char *name, const std::vector< std::string > &instances, const std::vector< port > &in_widths, const std::vector< port > &out_widths, unsigned vme_addr_width=0, bool distrRAM=false)
Initialize the LUT.