11 #include <trg/cdc/modules/trgcdc/CDCTriggerTSFFirmwareModule.h>
12 #include <trg/cdc/CDCTrigger.h>
13 #include <trg/cdc/Cosim.h>
14 #include <framework/datastore/StoreArray.h>
15 #include <framework/datastore/StoreObjPtr.h>
16 #include <framework/dataobjects/EventMetaData.h>
17 #include <trg/cdc/dataobjects/CDCTriggerSegmentHit.h>
18 #include <cdc/dataobjects/CDCHit.h>
19 #include <framework/logging/Logger.h>
33 using namespace Cosim;
35 using namespace CDCTrigger;
46 for (
unsigned iAx = 0; iAx < m_nSubModules; ++iAx) {
47 inputToTSF[iAx].resize(nAxialMergers[iAx]);
48 for (
auto& clock : m_priorityHit) {
49 clock.insert({2 * iAx, priorityHitStructInSL(nAxialMergers[iAx])});
51 dataAcrossClocks.insert({2 * iAx, mergerStruct<5> (nAxialMergers[iAx])});
54 setDescription(
"Firmware simulation of the Track Segment Finder for CDC trigger.");
57 addParam(
"hitCollectionName", m_hitCollectionName,
58 "Name of the input StoreArray of CDCHits.",
60 addParam(
"outputCollectionName", m_outputCollectionName,
61 "Name of the StoreArray holding the found TS hits.",
62 string(
"CDCTriggerFirmwareSegmentHits"));
63 addParam(
"outputBitstreamNameTo2D", m_outputBitstreamNameTo2D,
64 "Name of the StoreArray holding the raw bit content to 2D trackers",
65 string(
"BitstreamTSFto2D"));
66 addParam(
"mergerOnly", m_mergerOnly,
67 "Flag to only simulate merger and not TSF",
69 addParam(
"simulateCC", m_simulateCC,
70 "Flag to run the front-end clock counter",
72 std::vector<bool> defaultStub(m_nSubModules,
false);
73 addParam(
"stubLUT", m_stubLUT,
74 "list of flags to run each TSF firmware simulation with dummy L/R LUT (to speed up loading)",
78 TSF::~CDCTriggerTSFFirmwareModule()
83 CDCHit* hit = m_cdcHits[index];
84 int offset = (hit->getISuperLayer() == 0) ? 1 : 0;
85 switch (hit->getILayer() - 2 - offset) {
86 case 0:
return Priority::first;
87 case 1:
return Priority::second;
88 default:
return Priority::nothing;
95 fprintf(outstream,
"%s\n" , message);
102 array<char, 2048> buffer;
105 if (fgets(buffer.data(), buffer.size(), instream) == NULL) {
106 B2ERROR(
"fgets reached end unexpectedly");
110 for (
auto i2d = 0; i2d < 4; ++i2d) {
111 B2DEBUG(50,
display_value(buffer.data() + width_out * i2d, width_out));
113 auto bufferItr = buffer.cbegin();
115 for (
int iTracker = nTrackers - 1; iTracker >= 0; --iTracker) {
116 copy(bufferItr, bufferItr + width_out, output[iTracker].begin());
117 bufferItr += width_out;
124 m_cdcHits.isRequired(m_hitCollectionName);
125 m_debugLevel = getLogConfig().getDebugLevel();
130 m_bitsTo2D.registerInDataStore(m_outputBitstreamNameTo2D);
131 m_tsHits.registerInDataStore(m_outputCollectionName);
132 for (
unsigned i = 0; i < m_nSubModules; ++i) {
136 pipe(inputFileDescriptor[i].data());
137 pipe(outputFileDescriptor[i].data());
138 string str_fd[] = {to_string(inputFileDescriptor[i][0]), to_string(outputFileDescriptor[i][1])};
143 B2FATAL(
"Fork failed!");
144 }
else if (pid == (pid_t) 0) {
147 close(inputFileDescriptor[i][1]);
148 close(outputFileDescriptor[i][0]);
150 design_libname_post =
"_stub" + design_libname_post;
152 string design = design_libname_pre + to_string(i * 2) + design_libname_post;
153 string waveform = wdbName_pre + to_string(i * 2) + wdbName_post;
155 execlp(
"CDCTriggerTSFFirmwareWorker",
"CDCTriggerTSFFirmwareWorker",
156 str_fd[0].c_str(), str_fd[1].c_str(), design.c_str(), waveform.c_str(),
157 to_string(nAxialMergers[i]).c_str(),
nullptr);
158 B2FATAL(
"The firmware simulation program didn't launch!");
161 B2DEBUG(100,
"parent " << i);
164 close(inputFileDescriptor[i][0]);
165 close(outputFileDescriptor[i][1]);
167 stream[i][0] = fdopen(inputFileDescriptor[i][1],
"w");
168 stream[i][1] = fdopen(outputFileDescriptor[i][0],
"r");
170 B2DEBUG(20,
"pid for TSF" << i * 2 <<
": " << m_pid[i]);
174 B2INFO(
"It can take a while for TSF0 to load the LUT.");
175 for (
unsigned i = 0; i < m_nSubModules; ++i) {
183 B2DEBUG(10,
"Waiting for TSF firmware termination...");
184 for (
unsigned i = 0; i < m_nSubModules; ++i) {
185 close(inputFileDescriptor[i][1]);
186 close(outputFileDescriptor[i][0]);
189 for (
unsigned i = 0; i < m_nSubModules; ++i) {
196 for (
unsigned short iEdge = 0; iEdge < 5; ++iEdge) {
197 for (
const auto& cell : innerInvEdge[iEdge]) {
198 m_edge[0][cell].push_back(iEdge);
201 for (
unsigned short iEdge = 0; iEdge < 3; ++iEdge) {
202 for (
const auto& cell : outerInvEdge[iEdge]) {
203 m_edge[1][cell].push_back(iEdge);
211 static array<char, mergerWidth* nAxialMergers[iSL]> data;
215 for (
const auto& merger : input[iSL]) {
216 copy(merger.begin(), merger.end(), itr);
224 if (m_allPositiveTime) {
225 return (m_cdcHits[iFirstHit]->getTDCCount() / 2 - m_cdcHits[index]->getTDCCount() / 2);
227 short time = (m_TDCCountForT0 / 2 - m_cdcHits[index]->getTDCCount() / 2);
228 return (time < 0) ? time + (1 << 9) : time;
234 return std::bitset<4> (trgTime(index, iFirstHit) % clockPeriod);
239 const CDCHit& hit = (*m_cdcHits[index]);
240 const unsigned offset = (hit.getISuperLayer() == 0) ? 3 : 0;
241 return (hit.getILayer() - offset) * nSegmentsInMerger +
242 hit.getIWire() % nSegmentsInMerger;
247 const CDCHit& hit = (*m_cdcHits[index]);
248 return hit.getIWire() / nSegmentsInMerger;
251 using WireSet = std::vector<unsigned short>;
252 using TSMap = std::unordered_map<int, WireSet>;
256 const bool innerMost = (m_cdcHits[iHit]->getISuperLayer() == 0);
257 const unsigned short iLayer = m_cdcHits[iHit]->getILayer();
258 const unsigned short iCell = mergerCellID(iHit);
259 TSMap& tsMap = m_tsMap[
static_cast<int>(! innerMost)];
260 tsMap.reserve(nWiresInMerger);
261 if (tsMap.find(iCell) != tsMap.end()) {
267 const unsigned short distance = (innerMost) ? iLayer - 3 : abs(iLayer - 2);
268 id.resize(distance + 1);
269 std::iota(
id.begin(),
id.end(), (iCell - distance / 2) % nCellsInLayer);
270 id.erase(std::remove_if(
id.begin(),
id.end(), [](
short i) {
271 return (i < 0 || i >= nCellsInLayer);
273 tsMap.insert({iCell,
id});
285 vector<int> iAxialHit;
286 for (
int i = 0; i < m_cdcHits.getEntries(); ++i) {
288 if ((m_cdcHits[i]->getISuperLayer() != 0 && m_cdcHits[i]->getILayer() == 5) ||
289 m_cdcHits[i]->getICLayer() < 3) {
292 if (m_cdcHits[i]->getISuperLayer() % 2 == 0) {
293 iAxialHit.push_back(i);
297 std::sort(iAxialHit.begin(), iAxialHit.end(), [
this](
int i,
int j) {
298 return m_cdcHits[i]->getTDCCount() > m_cdcHits[j]->getTDCCount();
302 iAxialHitInClock.clear();
303 iAxialHitInClock.resize(1 + trgTime(iAxialHit.back(), iAxialHit.front()) / clockPeriod);
304 auto itr = iAxialHitInClock.begin();
306 for (
const auto& ihit : iAxialHit) {
307 B2DEBUG(20,
"sorted TDC count: " << m_cdcHits[ihit]->getTDCCount() <<
308 ", SL" << m_cdcHits[ihit]->getISuperLayer() <<
", layer" << m_cdcHits[ihit]->getILayer() <<
309 ", wire " << m_cdcHits[ihit]->getIWire() <<
", ihit: " << ihit);
315 while (trgTime(ihit, iAxialHit.front()) >= clockEdge * clockPeriod) {
319 itr->push_back(ihit);
321 m_iFirstHit = iAxialHit.front();
324 for (
auto& clock : m_priorityHit) {
325 for (
auto& sl : clock) {
326 for (
auto& merger : sl.second) {
335 return ! reg[field][iTS];
351 timeVec& priorityTime = (get<MergerOut::priorityTime>(mergerData))[priTS];
353 if (notHit(MergerOut::priorityTime, priTS, registeredCell)) {
354 priorityTime = hitTime;
355 registerHit(MergerOut::priorityTime, priTS, registeredCell);
356 get<MergerOut::secondPriorityHit>(mergerData)[0].set(priTS, ! lr);
357 priorityHit.insert({priTS, iHit});
359 }
else if (priority(priorityHit[priTS]) == Priority::second &&
360 hitTime.to_ulong() == priorityTime.to_ulong() && lr == 1) {
361 get<MergerOut::secondPriorityHit>(mergerData)[0].reset(priTS);
362 priorityHit[priTS] = iHit;
369 for (
auto& sl : inputToTSF) {
370 for (
auto& merger : sl) {
375 if (iClock >= iAxialHitInClock.size()) {
384 map<unsigned, mergerStruct<5> > dataInClock;
385 map<unsigned, registeredStruct> registered;
386 for (
int iAx = 0; iAx < m_nSubModules; ++iAx) {
390 auto clock = iAxialHitInClock[iClock];
393 std::stable_partition(clock.begin(), clock.end(),
394 [
this](
int hit) {return priority(hit) == Priority::first;});
395 for (
const auto& iHit : clock) {
396 const CDCHit& hit = *m_cdcHits[iHit];
397 const unsigned short iSL = hit.getISuperLayer();
398 const short outer = (iSL == 0) ? 0 : 1;
399 const unsigned short iMerger = mergerNumber(iHit);
400 const unsigned short iCell = mergerCellID(iHit);
401 const WireSet tsList = segmentID(iHit);
402 const timeVec hitTime = timeStamp(iHit, m_iFirstHit);
403 auto& mergerData = dataInClock[iSL][iMerger];
404 auto& registeredCell = registered[iSL][iMerger];
406 auto& priorityHit = m_priorityHit[iClock][iSL][iMerger];
407 B2DEBUG(50,
"iHit: " << iHit <<
", Merger" << iSL <<
"-" << iMerger <<
408 ", iCell: " << iCell);
410 get<MergerOut::hitmap>(mergerData)[0].set(iCell);
412 for (
const auto& iTS : tsList) {
413 timeVec& fastestTime = (get<MergerOut::fastestTime>(mergerData))[iTS];
415 if (notHit(MergerOut::fastestTime, iTS, registeredCell) ||
417 hitTime.to_ulong() < fastestTime.to_ulong()) {
421 fastestTime = hitTime;
422 registerHit(MergerOut::fastestTime, iTS, registeredCell);
426 if (m_edge[outer].find(iCell) != m_edge[outer].end()) {
427 for (
auto& iEdgeTime : m_edge[outer][iCell]) {
428 timeVec& edgeTime = (get<MergerOut::edgeTime>(mergerData))[iEdgeTime];
429 if (notHit(MergerOut::edgeTime, iEdgeTime, registeredCell) ||
430 hitTime.to_ulong() < edgeTime.to_ulong()) {
432 registerHit(MergerOut::edgeTime, iEdgeTime, registeredCell);
436 switch (priority(iHit)) {
437 case Priority::first: {
439 unsigned priTS = iCell % nSegmentsInMerger;
441 timeVec& priorityTime = (get<MergerOut::priorityTime>(mergerData))[priTS];
443 if (notHit(MergerOut::priorityTime, priTS, registeredCell)) {
444 priorityTime = hitTime;
445 registerHit(MergerOut::priorityTime, priTS, registeredCell);
446 get<MergerOut::secondPriorityHit>(mergerData)[0].reset(priTS);
447 priorityHit.insert({priTS, iHit});
451 case Priority::second: {
453 for (
unsigned i = 0; i < 2; ++i) {
454 unsigned priTS = iCell % nSegmentsInMerger + i;
455 if (priTS == nSegmentsInMerger) {
459 const unsigned short iMergerPlus1 = (iMerger == nMergers[iSL] - 1) ? 0 : iMerger + 1;
460 auto& nextMergerData = dataInClock[iSL][iMergerPlus1];
461 auto& nextRegisteredCell = registered[iSL][iMergerPlus1];
462 auto& nextPriorityHit = m_priorityHit[iClock][iSL][iMergerPlus1];
463 setSecondPriority(priTS, iHit, hitTime, i, nextMergerData, nextRegisteredCell, nextPriorityHit);
465 setSecondPriority(priTS, iHit, hitTime, i, mergerData, registeredCell, priorityHit);
475 for (
auto iAx = 0; iAx < m_nSubModules; ++iAx) {
476 unsigned nEdges = (iAx == 0) ? 5 : 3;
477 for (
unsigned iMerger = 0; iMerger < inputToTSF[iAx].size(); ++iMerger) {
478 auto input = inputToTSF[iAx][iMerger].rbegin();
479 auto& output = dataInClock[2 * iAx][iMerger];
480 pack<MergerOut::hitmap, 1> (input, nWiresInMerger, output);
481 pack<MergerOut::priorityTime, timeWidth> (input, nCellsInLayer, output);
482 pack<MergerOut::fastestTime, timeWidth> (input, nCellsInLayer, output);
483 pack<MergerOut::secondPriorityHit, 1> (input, nCellsInLayer, output);
484 pack<MergerOut::edgeTime, timeWidth> (input, nEdges, output);
486 auto& outputAcrossClocks = dataAcrossClocks[2 * iAx][iMerger];
487 if (get<MergerOut::hitmap>(output)[0].any()) {
488 string priTime, fasTime, edgTime;
489 for (
int i = 0; i < nSegmentsInMerger; ++i) {
490 priTime += get<MergerOut::priorityTime>(output)[i].to_string() +
",";
491 fasTime += get<MergerOut::fastestTime>(output)[i].to_string() +
",";
492 edgTime += get<MergerOut::edgeTime>(output)[i].to_string() +
",";
493 get<MergerOut::priorityTime>(outputAcrossClocks)[i] |=
494 get<MergerOut::priorityTime>(output)[i];
495 get<MergerOut::fastestTime>(outputAcrossClocks)[i] |=
496 get<MergerOut::fastestTime>(output)[i];
498 B2DEBUG(150,
"merger " << iAx * 2 <<
"-" << iMerger <<
499 "\nhitmap: " << get<MergerOut::hitmap>(output)[0] <<
500 "\nsecond hit: " << get<MergerOut::secondPriorityHit>(output)[0] <<
501 "\nprioiry Time: " << priTime <<
502 "\nfastest Time: " << fasTime <<
503 "\nedge Time: " << edgTime);
504 get<MergerOut::hitmap>(outputAcrossClocks)[0] |= get<MergerOut::hitmap>(output)[0];
508 bitset<9> cc(iClock);
509 const int nBitsReserved = (iAx == 0) ? 3 : 4;
510 generate(inputToTSF[iAx][iMerger].rend() - 9 - nBitsReserved,
511 inputToTSF[iAx][iMerger].rend() - nBitsReserved,
512 [&cc, i = 0]()
mutable {
519 template<MergerOut field,
size_t w
idth>
520 void TSF::pack(inputVector::reverse_iterator& input,
unsigned number,
523 std::generate(input, input + number * width, [&, n = 0]()
mutable {
529 return (get<field>(output)[i / width][i % width]) ?
one_val :
zero_val;}});
530 input += number * width;
535 m_bitsTo2D.appendNew(outputToTracker);
542 const int ccWidth = 9;
544 const int widenedClocks = 16;
546 const int latency = 3;
550 for (
const auto& sl : outputToTracker) {
553 std::map<unsigned, int> foundTS;
554 unsigned short iTracker = 0;
555 for (
auto& tracker : sl) {
558 for (
int i = ccWidth; i < width_out; i += tsInfoWidth) {
559 string ts = output.substr(i, tsInfoWidth);
560 tsOut decoded = decodeTSHit(ts);
562 if (decoded[3] == 0) {
565 const unsigned nCellsInSL = nAxialMergers[iAx] * nCellsInLayer;
567 unsigned iTS = decoded[0] + nCellsInSL * iTracker / nTrackers;
569 if (iTS >= nCellsInSL) {
580 int firstClock = iclock - widenedClocks - latency;
581 if (firstClock < 0) {
584 int lastClock = iclock - latency;
585 B2DEBUG(10,
"iAx:" << iAx <<
", iTS:" << iTS <<
", iTracker: " << iTracker);
587 for (
int iclkPri = firstClock; iclkPri < lastClock; ++iclkPri) {
589 auto priMap = m_priorityHit[iclkPri][2 * iAx][iTS / nSegmentsInMerger];
590 unsigned itsInMerger = iTS % nSegmentsInMerger;
593 if (priMap.find(itsInMerger) != priMap.end() &&
594 toPriority(decoded[3]) == priority(priMap[itsInMerger])) {
595 iHit = priMap[itsInMerger];
596 B2DEBUG(10,
"iHit:" << iHit);
597 B2DEBUG(10,
"TDC: " << m_cdcHits[iHit]->getTDCCount() <<
", TSF: " << decoded[1]);
605 if (foundTS.find(iTS) != foundTS.end()) {
606 if (iHit != foundTS[iTS]) {
607 B2WARNING(
"Same TS ID exists, but they point to different CDC hit");
611 foundTS.insert({iTS, iHit});
613 B2WARNING(
"No corresponding priority CDC hit can be found.");
614 B2WARNING(
"Maybe the latency and number of widened clocks are wrong.");
616 B2DEBUG(20,
"priority " << decoded[3]);
617 for (
int iclkPri = 0; iclkPri < m_nClockPerEvent; ++iclkPri) {
618 auto priMap = m_priorityHit[iclkPri][2 * iAx][iTS / 16];
619 for (
auto& m : priMap) {
620 B2DEBUG(20,
"iWire: " << m.first <<
", iLayer: " <<
621 m_cdcHits[m.second]->getILayer() <<
", iClock: " << iclkPri);
625 B2WARNING(
"It could be the left over TS hits from the last event.\n" <<
626 "Try increasing m_nClockPerEvent");
629 CDCHit cdchit = (iHit < 0) ?
CDCHit() : *m_cdcHits[iHit];
630 m_tsHits.appendNew(cdchit,
631 globalSegmentID(iTS, 2 * iAx),
654 for (
unsigned iAx = 0; iAx < m_nSubModules; ++iAx) {
657 for (
int iClock = 0; iClock < m_nClockPerEvent; iClock++) {
658 B2INFO(
string(15,
'=') <<
" clock #" << iClock <<
" " <<
string(15,
'='));
659 if (iClock == m_nClockPerEvent - 1) {
660 cout <<
"Accumulative hitmap:" <<
"\n";
662 simulateMerger(iClock);
666 for (
const auto& sl : inputToTSF) {
668 for (
const auto& mergerOut : sl) {
669 if (std::any_of(mergerOut.begin(), mergerOut.end(), [](
char i) {
670 return i != zero_val;
672 cout <<
"Merger " << iSL * 2 <<
"-" << iMerger / 2 <<
" u" << iMerger % 2 <<
": ";
676 if (iClock == m_nClockPerEvent - 1) {
677 auto accuOut = dataAcrossClocks[2 * iSL][iMerger];
678 if (get<MergerOut::hitmap>(accuOut)[0].any()) {
679 cout <<
"Merger " << iSL * 2 <<
"-" << iMerger / 2 <<
" u" << iMerger % 2 <<
": ";
680 cout << get<MergerOut::hitmap>(accuOut)[0] <<
"\n";
681 string priTime, fasTime;
682 for (
int i = 0; i < 16; ++i) {
683 priTime += get<MergerOut::priorityTime>(accuOut)[i].to_string() +
",";
684 fasTime += get<MergerOut::fastestTime>(accuOut)[i].to_string() +
",";
686 cout <<
"pritime: " << priTime <<
"\n";
687 cout <<
"fastime: " << fasTime <<
"\n";
698 auto TSF0 = getData<0>(inputToTSF);
699 auto TSF2 = getData<1>(inputToTSF);
700 auto TSF4 = getData<2>(inputToTSF);
701 auto TSF6 = getData<3>(inputToTSF);
702 auto TSF8 = getData<4>(inputToTSF);
703 array<char*, m_nSubModules> rawInputToTSF = {TSF0, TSF2, TSF4, TSF6, TSF8};
705 for (
unsigned iSL = 0; iSL < m_nSubModules; ++iSL) {
706 B2DEBUG(100,
"input to TSF" << iSL * 2 <<
": \n" <<
708 write(rawInputToTSF[iSL], stream[iSL][0]);
711 if (m_debugLevel >= 50) {
712 usleep(2000 * m_debugLevel);
714 for (
unsigned iSL = 0; iSL < m_nSubModules; ++iSL) {
715 B2DEBUG(50,
"Reading buffer from TSF " << iSL * 2 <<
":");
716 outputToTracker[iSL] = read(stream[iSL][1]);
717 B2DEBUG(30,
"received TSF " << iSL * 2 <<
":");
718 if (m_debugLevel >= 30) {
719 for (
const auto& out : outputToTracker[iSL]) {
724 saveFirmwareOutput();
725 saveFastOutput(iClock);
727 }
catch (std::exception& e) {
728 B2ERROR(
"ERROR: An exception occurred: " << e.what());
731 B2ERROR(
"ERROR: An unknown exception occurred.");
734 B2DEBUG(50,
"status code:" << status);