24 #include <boost/algorithm/string.hpp>
36 if (!m_UseLookupFunction) {
47 const vector<string>& instances,
48 const vector<port>& in_widths,
49 const vector<port>& out_widths,
50 unsigned vme_addr_width,
53 m_InstNames = instances;
54 m_NLUTS = instances.size();
58 for (
unsigned i = 0;
i < in_widths.size();
i++)
59 m_TotalInWidth += in_widths[
i].
second;
61 m_Outputs = out_widths;
63 for (
unsigned i = 0;
i < out_widths.size();
i++)
64 m_TotalOutWidth += out_widths[
i].
second;
66 m_vme_addr_width = vme_addr_width;
67 m_distrRAM = distrRAM;
69 if (m_distrRAM && (m_TotalInWidth != vme_addr_width)) {
70 edm::LogWarning(
"AddressMismatch") <<
"L1MuGMTLUT::Init(): for distributed RAM the GMT (Input) address width "
71 <<
"has to match the VME address width. Core Generation will not work.";
80 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Save: LUT not initialized. ";
87 of <<
"// This is a CMS L1 Global Muon Trigger .lut file. " << endl;
89 of <<
"// It defines a set of look-up-tables(LUTs) of the same type (same inputs and outputs) but" << endl;
90 of <<
"// with different default contents. For example a certain type of LUT can have different" << endl;
91 of <<
"// default values for DT for RPC and for CSC muons. " << endl;
93 of <<
"// NAME gives the name of the LUT. It should match the base name (name without '.lut')" << endl;
94 of <<
"// of the LUT file." << endl;
95 of <<
"// When deriving a C++ sub-class the name is used case sensitive." << endl;
96 of <<
"// In generated VHDL code the name is used in lower case." << endl;
98 of <<
"// INSTANCES is the list of instances of the LUT with different default values." << endl;
99 of <<
"// the lists consists of identifiers for each of the instances separated by spaces." << endl;
100 of <<
"// the identifiers can be made up of characters that are valid in VHDL lables. " << endl;
101 of <<
"// In the VHDL code they are used to label the different instances." << endl;
103 of <<
"// In C++ and VHDL the instance of a LUT is selected by an integer index where 0 " << endl;
104 of <<
"// corresponds to the leftmost identifier. Integer indices are also used in the CONTENTS_XX"
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"
110 of <<
"// <input_name>(<number_of_bits>) where <input_name> is the name of the input and" << endl;
111 of <<
"// <number_of_bits> is the number of bits of the input. <input_name> has to be a valid" << endl;
112 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
114 of <<
"// All LUT inputs together make up the address of the corresponding memory." << endl;
115 of <<
"// The first input in the list corresponds to the most-significant bits of the address."
118 of <<
"// LUT_OUTPUTS is the (space-separated) list of outputs of the LUT. Each output is specified in the form"
120 of <<
"// <output_name>(<number_of_bits>) where <output_name> is the name of the output and" << endl;
121 of <<
"// <number_of_bits> is the number of bits of the output. <output_name> has to be a valid"
123 of <<
"// identifier both in C++ and in VHDL. In C++ it is represented as an unsigned int." << endl;
125 of <<
"// All LUT outputs together make up the data of the corresponding memory." << endl;
126 of <<
"// The first output in the list corresponds to the most-significant data bits." << endl;
128 of <<
"// VME_ADDR_WIDTH is the address width of the LUT memory when accessed via VME. When the LUT " << endl;
129 of <<
"// is implemented as dual-port block RAM, the VME address with can be different " << endl;
130 of <<
"// from the address width given by the sum of the input widths. It can be larger or" << endl;
131 of <<
"// smaller by a factor of 2^n. When the LUT is implemented as dual-port distributed RAM,"
133 of <<
"// the VME address width has to match the input width. " << endl;
135 of <<
"// DISTRIBUTED_RAM is 1 if the LUT is to be implemented in distributed RAM and 0 for Block RAM " << endl;
136 of <<
"// Note that for distributed RAM the address width on the GMT side (sum of input widths)"
138 of <<
"// has to match the vme_addr_width" << endl;
140 of <<
"// CONTENTS_XX specifies the default contents of instance with index XX (see INSTANCES)." << endl;
141 of <<
"// contents are specified as decimal numbers, one number per line." << endl;
143 of <<
"// Hannes Sakulin / HEPHY Vienna, 2003" << endl;
146 of <<
"NAME = " << m_name << endl;
148 for (
unsigned i = 0;
i < m_InstNames.size();
i++)
149 of <<
" " << m_InstNames[
i];
153 of <<
"VME_ADDR_WIDTH = " << m_vme_addr_width << endl;
154 of <<
"DISTRIBUTED_RAM = " << (m_distrRAM ?
"1" :
"0") << endl;
155 for (
int i = 0;
i < m_NLUTS;
i++) {
156 of <<
"// " << m_InstNames[
i] << endl;
157 of <<
"CONTENTS_" <<
i <<
" = ";
158 for (
unsigned addr = 0;
addr < (unsigned)(1 << m_TotalInWidth);
addr++) {
159 of << LookupPacked(
i,
addr) << endl;
178 if (!m_initialized) {
179 edm::LogWarning(
"LUTNotInitialized") <<
"L1MuGMTLUT::Set: LUT not initialized. ";
183 if (
idx >= m_NLUTS) {
184 edm::LogWarning(
"LUTRangeViolation") <<
"L1MuGMTLUT::Set: LUT index exceeds range (0 to " << (m_NLUTS - 1) <<
").";
187 if (address >= (
unsigned)(1 << m_TotalInWidth)) {
188 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT input exceeds range (0 to "
189 << ((1 << m_TotalInWidth) - 1) <<
").";
192 if (
value >= (
unsigned)(1 << m_TotalOutWidth)) {
193 edm::LogWarning(
"LUTRangeViolation") <<
"Error in L1MuGMTLUT::Set: LUT output exceeds range (0 to "
194 << ((1 << m_TotalOutWidth) - 1) <<
").";
202 vector<string> lf_InstNames;
203 vector<port> lf_Inputs;
204 vector<port> lf_Outputs;
205 unsigned lf_vme_addr_width = 0;
206 bool lf_distrRAM =
false;
207 vector<string> lf_comments;
215 while (
in.getline(
buf, sz)) {
218 if ((
i =
line.find(
"//")) != string::npos) {
219 lf_comments.push_back(
line.substr(
i));
223 if (tok.size() == 2) {
229 tok[1].erase(0, tok[1].find_first_not_of(
" "));
230 tok[1].erase(tok[1].find_last_not_of(
" ") + 1);
232 if (tok[0] ==
"NAME")
234 else if (tok[0] ==
"INSTANCES") {
236 }
else if (tok[0] ==
"LUT_INPUTS")
238 else if (tok[0] ==
"LUT_OUTPUTS")
240 else if (tok[0] ==
"VME_ADDR_WIDTH")
241 lf_vme_addr_width = atoi(tok[1].c_str());
242 else if (tok[0] ==
"DISTRIBUTED_RAM")
243 lf_distrRAM = (atoi(tok[1].c_str()) == 1);
245 if (tok[0].
find(
"CONTENTS") != string::npos)
249 if (!m_initialized) {
250 Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
252 if (m_name != lf_name || m_InstNames != lf_InstNames || m_Inputs != lf_Inputs || m_Outputs != lf_Outputs ||
253 m_vme_addr_width != lf_vme_addr_width || m_distrRAM != lf_distrRAM) {
255 <<
"L1MuGMTLUT::Load: error: parameters in file do not match configuration of LUT. Load failed.";
260 if (m_UseLookupFunction) {
262 m_Contents.resize(m_NLUTS);
263 for (
int i = 0;
i < m_NLUTS;
i++)
264 m_Contents[
i].resize(1 << m_TotalInWidth);
267 m_UseLookupFunction =
false;
271 int maxrows = 1 << m_TotalInWidth;
273 int current_index = -1;
277 if ((
i =
line.find(
"//")) != string::npos)
281 if (tok.size() == 2 && tok[0].find(
"CONTENTS") != string::npos) {
283 if (tok1.size() != 2) {
284 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: error parsing contents tag " << tok[0] <<
".";
288 istringstream is(tok1[1]);
291 if (newindex != current_index + 1)
292 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUTS in LUT file are not in order.";
294 if (newindex > m_NLUTS - 1) {
295 edm::LogWarning(
"LUTParsingProblem") <<
"L1MuGMTLUT::Load: warning: LUT file contains LUT with too high index ("
296 << tok[0] <<
"). max = " << m_NLUTS <<
" skipping.";
299 current_index = newindex;
304 <<
"L1MuGMTLUT::Load: warning: LUT file only contains part of LUT contents.";
307 istringstream is1(tok[1]);
310 if (current_index != -1)
311 Set(current_index, row++,
value);
314 istringstream is1(
line);
318 if (current_index != -1)
319 Set(current_index, row++,
value);
322 <<
"L1MuGMTLUT::Load: warning: LUT file only contains LUT with too many entries. skipping.";
325 }
while (
in.getline(
buf, sz));
335 string ins_name(m_name);
336 string ins_name_upper = boost::to_upper_copy(ins_name);
337 string ins_instance_string;
338 string ins_instances_enum;
339 for (
unsigned i = 0;
i < m_InstNames.size();
i++) {
341 ins_instance_string +=
' ';
342 ins_instance_string += m_InstNames[
i];
345 ins_instances_enum +=
", ";
346 ins_instances_enum += m_InstNames[
i];
349 sprintf(ins_vme,
"%d", m_vme_addr_width);
351 char ins_distr_RAM[10];
352 sprintf(ins_distr_RAM,
"%s", m_distrRAM ?
"true" :
"false");
354 string ins_input_decl_list, ins_input_list, ins_input_addr_list;
355 for (
unsigned i = 0;
i < m_Inputs.size();
i++) {
356 ins_input_decl_list +=
string(
", unsigned ") + m_Inputs[
i].first;
357 ins_input_list +=
string(
", ") + m_Inputs[
i].first;
359 sprintf(
tmp,
" ,addr[%d]",
i);
365 for (
unsigned i = 0;
i < m_Outputs.size();
i++) {
366 os <<
" /// specific lookup function for " << m_Outputs[
i].first << endl;
367 os <<
" unsigned SpecificLookup_" << m_Outputs[
i].first <<
" (int idx" << ins_input_decl_list <<
") const {"
369 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
370 for (
unsigned j = 0;
j < m_Inputs.size();
j++) {
371 os <<
" addr[" <<
j <<
"] = " << m_Inputs[
j].first <<
";" << endl;
373 os <<
" return Lookup(idx, addr) [" <<
i <<
"];" << endl;
374 os <<
" };" << endl << endl;
376 os <<
" /// specific lookup function for entire output field" << endl;
377 os <<
" unsigned SpecificLookup (int idx" << ins_input_decl_list <<
") const {" << endl;
378 os <<
" vector<unsigned> addr(" << m_Inputs.size() <<
");" << endl;
379 for (
unsigned j = 0;
j < m_Inputs.size();
j++) {
380 os <<
" addr[" <<
j <<
"] = " << m_Inputs[
j].first <<
";" << endl;
382 os <<
" return LookupPacked(idx, addr);" << endl;
383 os <<
" };" << endl << endl;
386 string ins_lookup_functions = os.str();
391 outfn =
string(
"../interface/L1MuGMT") + m_name +
string(
"LUT.h");
392 ifstream of_check(outfn.c_str());
393 if (!of_check.good()) {
394 ofstream of(outfn.c_str());
396 ifstream
in(template_file_h);
400 while (
in.getline(
buf, sz)) {
420 string outfn_cc(
fname);
421 if (outfn_cc.empty())
422 outfn_cc =
string(
"../interface/L1MuGMT") + m_name +
string(
"LUT.cc");
424 ifstream of_cc_check(outfn_cc.c_str());
425 if (!of_cc_check.good()) {
426 ofstream of_cc(outfn_cc.c_str());
428 ifstream in_cc(template_file_cc);
432 while (in_cc.getline(
buf, sz)) {
447 of_cc <<
line << endl;