File indexing completed on 2024-04-06 12:19:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
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
0038
0039
0040
0041
0042
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
0168
0169
0170
0171
0172
0173
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
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));
0220 line.erase(i);
0221 }
0222 L1MuGMTLUTHelpers::Tokenizer tok("=", line);
0223 if (tok.size() == 2) {
0224 L1MuGMTLUTHelpers::replace(tok[0], " ", "", false);
0225 L1MuGMTLUTHelpers::replace(tok[0], "\t", "", false);
0226
0227 L1MuGMTLUTHelpers::replace(tok[1], "\t", " ", false);
0228 L1MuGMTLUTHelpers::replace(tok[1], " ", " ", true);
0229 tok[1].erase(0, tok[1].find_first_not_of(' '));
0230 tok[1].erase(tok[1].find_last_not_of(' ') + 1);
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) {
0250 Init(lf_name.c_str(), lf_InstNames, lf_Inputs, lf_Outputs, lf_vme_addr_width, lf_distrRAM);
0251 } else {
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
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
0267 m_UseLookupFunction = false;
0268 }
0269
0270
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);
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
0330
0331
0332
0333 void L1MuGMTLUT::MakeSubClass(const char* fname, const char* template_file_h, const char* template_file_cc) {
0334
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
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
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
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 }