38 if (! m_UseLookupFunction ) {
50 const vector<port>& in_widths,
const vector<port>& out_widths,
51 unsigned vme_addr_width,
bool distrRAM)
54 m_InstNames = instances;
55 m_NLUTS = instances.size();
59 for (
unsigned i=0;
i< in_widths.size();
i++) m_TotalInWidth += in_widths[
i].
second;
61 m_Outputs = out_widths;
63 for (
unsigned i=0;
i< out_widths.size();
i++) m_TotalOutWidth += out_widths[
i].
second;
65 m_vme_addr_width = vme_addr_width;
66 m_distrRAM = distrRAM;
68 if (m_distrRAM && (m_TotalInWidth != vme_addr_width) ) {
70 <<
"L1MuGMTLUT::Init(): for distributed RAM the GMT (Input) address width "
71 <<
"has to match the VME address width. Core Generation will not work.";
80 if (! m_initialized) {
81 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Save: LUT not initialized. ";
88 of <<
"// This is a CMS L1 Global Muon Trigger .lut file. " << endl;
90 of <<
"// It defines a set of look-up-tables(LUTs) of the same type (same inputs and outputs) but" << endl;
91 of <<
"// with different default contents. For example a certain type of LUT can have different" << endl;
92 of <<
"// default values for DT for RPC and for CSC muons. " << endl;
94 of <<
"// NAME gives the name of the LUT. It should match the base name (name without '.lut')" << endl;
95 of <<
"// of the LUT file." << endl;
96 of <<
"// When deriving a C++ sub-class the name is used case sensitive." << endl;
97 of <<
"// In generated VHDL code the name is used in lower case." << endl;
99 of <<
"// INSTANCES is the list of instances of the LUT with different default values." << endl;
100 of <<
"// the lists consists of identifiers for each of the instances separated by spaces." << endl;
101 of <<
"// the identifiers can be made up of characters that are valid in VHDL lables. " << endl;
102 of <<
"// In the VHDL code they are used to label the different instances." << endl;
104 of <<
"// In C++ and VHDL the instance of a LUT is selected by an integer index where 0 " << endl;
105 of <<
"// corresponds to the leftmost identifier. Integer indices are also used in the CONTENTS_XX" << endl;
106 of <<
"// statements in this file." << endl;
108 of <<
"// LUT_INPUTS is the (space-separated) list of inputs of the LUT. Each input is specified in the form" << endl;
109 of <<
"// <input_name>(<number_of_bits>) where <input_name> is the name of the input and" << endl;
110 of <<
"// <number_of_bits> is the number of bits of the input. <input_name> has to be a valid" << endl;
111 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
113 of <<
"// All LUT inputs together make up the address of the corresponding memory." << endl;
114 of <<
"// The first input in the list corresponds to the most-significant bits of the address." << endl;
116 of <<
"// LUT_OUTPUTS is the (space-separated) list of outputs of the LUT. Each output is specified in the form" << endl;
117 of <<
"// <output_name>(<number_of_bits>) where <output_name> is the name of the output and" << endl;
118 of <<
"// <number_of_bits> is the number of bits of the output. <output_name> has to be a valid" << endl;
119 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
121 of <<
"// All LUT outputs together make up the data of the corresponding memory." << endl;
122 of <<
"// The first output in the list corresponds to the most-significant data bits." << endl;
124 of <<
"// VME_ADDR_WIDTH is the address width of the LUT memory when accessed via VME. When the LUT " << endl;
125 of <<
"// is implemented as dual-port block RAM, the VME address with can be different " << endl;
126 of <<
"// from the address width given by the sum of the input widths. It can be larger or" << endl;
127 of <<
"// smaller by a factor of 2^n. When the LUT is implemented as dual-port distributed RAM," << endl;
128 of <<
"// the VME address width has to match the input width. " << endl;
130 of <<
"// DISTRIBUTED_RAM is 1 if the LUT is to be implemented in distributed RAM and 0 for Block RAM " << endl;
131 of <<
"// Note that for distributed RAM the address width on the GMT side (sum of input widths)" << endl;
132 of <<
"// has to match the vme_addr_width" << endl;
134 of <<
"// CONTENTS_XX specifies the default contents of instance with index XX (see INSTANCES)." << endl;
135 of <<
"// contents are specified as decimal numbers, one number per line." << endl;
137 of <<
"// Hannes Sakulin / HEPHY Vienna, 2003" << endl;
140 of <<
"NAME = " << m_name << endl;
141 of <<
"INSTANCES =" ;
142 for (
unsigned i=0;
i<m_InstNames.size();
i++) of <<
" " << m_InstNames[
i];
146 of <<
"VME_ADDR_WIDTH = " << m_vme_addr_width << endl;
147 of <<
"DISTRIBUTED_RAM = " << (m_distrRAM?
"1":
"0") << endl;
148 for (
int i=0;
i<m_NLUTS;
i++) {
149 of <<
"// " << m_InstNames[
i] << endl;
150 of <<
"CONTENTS_" <<
i <<
" = ";
151 for (
unsigned addr = 0; addr < (unsigned) (1<<m_TotalInWidth); addr ++) {
152 of << LookupPacked (i, addr) << endl;
174 if (! m_initialized) {
175 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Set: LUT not initialized. ";
179 if ( idx >= m_NLUTS ) {
180 edm::LogWarning(
"LUTRangeViolation") <<
"L1MuGMTLUT::Set: LUT index exceeds range (0 to " << ( m_NLUTS -1 ) <<
").";
183 if ( address >= (
unsigned)(1 << m_TotalInWidth) ) {
184 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT input exceeds range (0 to " << ( (1 << m_TotalInWidth) -1 ) <<
").";
187 if ( value >= (
unsigned)(1 << m_TotalOutWidth) ) {
188 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT output exceeds range (0 to " << ( (1 << m_TotalOutWidth) -1 ) <<
")." ;
198 vector <string> lf_InstNames;
199 vector <port> lf_Inputs;
200 vector <port> lf_Outputs;
201 unsigned lf_vme_addr_width=0;
202 bool lf_distrRAM=
false;
203 vector<string> lf_comments;
206 const int sz=1000;
char buf[sz];
211 while ( in.getline(buf, sz) ) {
214 if ( (i=line.find(
"//")) != string::npos) {
215 lf_comments.push_back( line.substr(i) );
219 if (tok.size() == 2) {
225 tok[1].erase(0, tok[1].find_first_not_of(
" "));
226 tok[1].erase(tok[1].find_last_not_of(
" ")+1);
228 if (tok[0] ==
"NAME") lf_name = tok[1];
230 else if (tok[0] ==
"LUT_INPUTS") lf_Inputs =
PortDecoder(tok[1]);
231 else if (tok[0] ==
"LUT_OUTPUTS") lf_Outputs =
PortDecoder(tok[1]);
232 else if (tok[0] ==
"VME_ADDR_WIDTH") lf_vme_addr_width = atoi(tok[1].c_str());
233 else if (tok[0] ==
"DISTRIBUTED_RAM") lf_distrRAM = ( atoi(tok[1].c_str()) == 1 );
235 if (tok[0].
find(
"CONTENTS") != string::npos)
break;
238 if (!m_initialized) {
239 Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
242 if (m_name != lf_name ||
243 m_InstNames != lf_InstNames ||
244 m_Inputs != lf_Inputs ||
245 m_Outputs != lf_Outputs ||
246 m_vme_addr_width != lf_vme_addr_width ||
247 m_distrRAM != lf_distrRAM) {
249 <<
"L1MuGMTLUT::Load: error: parameters in file do not match configuration of LUT. Load failed.";
254 if (m_UseLookupFunction) {
256 m_Contents.resize( m_NLUTS );
257 for (
int i=0;
i < m_NLUTS;
i++)
258 m_Contents[
i].resize( 1 << m_TotalInWidth );
261 m_UseLookupFunction =
false;
265 int maxrows = 1 << m_TotalInWidth;
267 int current_index = -1;
271 if ( (i=line.find(
"//")) != string::npos) line.erase(i);
274 if (tok.size() == 2 && tok[0].find(
"CONTENTS") != string::npos) {
276 if (tok1.size() !=2) {
277 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: error parsing contents tag " << tok[0] <<
".";
281 istringstream is(tok1[1].c_str());
284 if (newindex != current_index+1)
285 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUTS in LUT file are not in order.";
287 if (newindex > m_NLUTS-1) {
288 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUT file contains LUT with too high index ("
290 <<
"). max = " << m_NLUTS <<
" skipping.";
293 current_index = newindex;
297 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUT file only contains part of LUT contents.";
300 istringstream is1(tok[1].c_str());
303 if (current_index!=-1)
304 Set (current_index, row++, value);
308 istringstream is1(line.c_str());
312 if (current_index!=-1)
313 Set (current_index, row++, value);
317 <<
"L1MuGMTLUT::Load: warning: LUT file only contains LUT with too many entries. skipping.";
320 }
while ( in.getline(buf, sz) );
329 const char* template_file_cc) {
332 string ins_name (m_name);
334 string ins_instance_string;
335 string ins_instances_enum;
336 for (
unsigned i=0;
i<m_InstNames.size();
i++) {
337 if (
i!=0) ins_instance_string +=
' ';
338 ins_instance_string += m_InstNames[
i];
340 if (
i!=0) ins_instances_enum +=
", ";
341 ins_instances_enum += m_InstNames[
i];
344 sprintf (ins_vme,
"%d", m_vme_addr_width);
346 char ins_distr_RAM[10];
347 sprintf (ins_distr_RAM,
"%s", m_distrRAM?
"true":
"false");
350 string ins_input_decl_list, ins_input_list, ins_input_addr_list;
351 for (
unsigned i=0;
i<m_Inputs.size();
i++) {
352 ins_input_decl_list += string(
", unsigned ") + m_Inputs[
i].first;
353 ins_input_list += string(
", ") + m_Inputs[
i].first;
354 char tmp[100]; sprintf (tmp,
" ,addr[%d]",
i);
355 ins_input_addr_list += string(tmp);
360 for (
unsigned i=0;
i<m_Outputs.size();
i++) {
361 os <<
" /// specific lookup function for " << m_Outputs[
i].first << endl;
362 os <<
" unsigned SpecificLookup_" << m_Outputs[
i].first <<
" (int idx" << ins_input_decl_list <<
") const {" << endl;
363 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
364 for (
unsigned j=0;
j< m_Inputs.size();
j++) {
365 os <<
" addr[" <<
j <<
"] = " << m_Inputs[
j].first <<
";" << endl;
367 os <<
" return Lookup(idx, addr) [" <<
i <<
"];" << endl;
368 os <<
" };" << endl << endl;
370 os <<
" /// specific lookup function for entire output field" << endl;
371 os <<
" unsigned SpecificLookup (int idx" << ins_input_decl_list <<
") const {" << endl;
372 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
373 for (
unsigned j=0;
j< m_Inputs.size();
j++) {
374 os <<
" addr[" <<
j <<
"] = " << m_Inputs[
j].first <<
";" << endl;
376 os <<
" return LookupPacked(idx, addr);" << endl;
377 os <<
" };" << endl << endl;
380 string ins_lookup_functions = os.str();
383 string outfn (fname);
384 if (outfn.size() == 0) outfn =
string(
"../interface/L1MuGMT") + m_name + string(
"LUT.h");
385 ifstream of_check(outfn.c_str());
386 if (! of_check.good() ) {
387 ofstream of(outfn.c_str());
390 ifstream
in(template_file_h);
391 const int sz=1000;
char buf[sz];
393 while ( in.getline(buf, sz) ) {
413 string outfn_cc (fname);
414 if (outfn_cc.size() == 0) outfn_cc =
string(
"../interface/L1MuGMT") + m_name + string(
"LUT.cc");
416 ifstream of_cc_check( outfn_cc.c_str() );
417 if (! of_cc_check.good() ) {
418 ofstream of_cc(outfn_cc.c_str());
421 ifstream in_cc(template_file_cc);
422 const int sz=1000;
char buf[sz];
424 while ( in_cc.getline(buf, sz) ) {
439 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
static std::string upperCase(const std::string &s)
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.