9#include <trg/cdc/modules/trgcdc/CDCTriggerTSFFirmwareModule.h>
10#include <trg/cdc/CDCTrigger.h>
11#include <trg/cdc/Cosim.h>
12#include <framework/datastore/StoreArray.h>
13#include <framework/datastore/StoreObjPtr.h>
14#include <framework/dataobjects/EventMetaData.h>
15#include <trg/cdc/dataobjects/CDCTriggerSegmentHit.h>
16#include <cdc/dataobjects/CDCHit.h>
17#include <framework/logging/Logger.h>
33using namespace CDCTrigger;
52 setDescription(
"Firmware simulation of the Track Segment Finder for CDC trigger.");
56 "Name of the input StoreArray of CDCHits.",
59 "Name of the StoreArray holding the found TS hits.",
60 string(
"CDCTriggerFirmwareSegmentHits"));
62 "Name of the StoreArray holding the raw bit content to 2D trackers",
63 string(
"BitstreamTSFto2D"));
65 "Flag to only simulate merger and not TSF",
68 "Flag to run the front-end clock counter",
72 "list of flags to run each TSF firmware simulation with dummy L/R LUT (to speed up loading)",
76TSF::~CDCTriggerTSFFirmwareModule()
82 int offset = (hit->getISuperLayer() == 0) ? 1 : 0;
83 switch (hit->getILayer() - 2 - offset) {
84 case 0:
return Priority::first;
85 case 1:
return Priority::second;
86 default:
return Priority::nothing;
93 fprintf(outstream,
"%s\n", message);
100 array<char, 2048> buffer;
103 if (fgets(buffer.data(), buffer.size(), instream) == NULL) {
104 B2ERROR(
"fgets reached end unexpectedly");
108 for (
auto i2d = 0; i2d < 4; ++i2d) {
111 auto bufferItr = buffer.cbegin();
113 for (
int iTracker =
nTrackers - 1; iTracker >= 0; --iTracker) {
114 copy(bufferItr, bufferItr +
width_out, output[iTracker].begin());
141 B2FATAL(
"Fork failed!");
142 }
else if (pid == (pid_t) 0) {
153 execlp(
"CDCTriggerTSFFirmwareWorker",
"CDCTriggerTSFFirmwareWorker",
154 str_fd[0].c_str(), str_fd[1].c_str(), design.c_str(), waveform.c_str(),
156 B2FATAL(
"The firmware simulation program didn't launch!");
159 B2DEBUG(100,
"parent " << i);
168 B2DEBUG(20,
"pid for TSF" << i * 2 <<
": " <<
m_pid[i]);
172 B2INFO(
"It can take a while for TSF0 to load the LUT.");
181 B2DEBUG(10,
"Waiting for TSF firmware termination...");
194 for (
unsigned short iEdge = 0; iEdge < 5; ++iEdge) {
196 m_edge[0][cell].push_back(iEdge);
199 for (
unsigned short iEdge = 0; iEdge < 3; ++iEdge) {
201 m_edge[1][cell].push_back(iEdge);
209 static array<char, mergerWidth* nAxialMergers[iSL]> data;
213 for (
const auto& merger : input[iSL]) {
214 copy(merger.begin(), merger.end(), itr);
223 return (
m_cdcHits[iFirstHit]->getTDCCount() / 2 -
m_cdcHits[index]->getTDCCount() / 2);
226 return (time < 0) ? time + (1 << 9) : time;
238 const unsigned offset = (hit.getISuperLayer() == 0) ? 3 : 0;
249using WireSet = std::vector<unsigned short>;
250using TSMap = std::unordered_map<int, WireSet>;
254 const bool innerMost = (
m_cdcHits[iHit]->getISuperLayer() == 0);
255 const unsigned short iLayer =
m_cdcHits[iHit]->getILayer();
259 if (tsMap.find(iCell) != tsMap.end()) {
265 const unsigned short distance = (innerMost) ? iLayer - 3 : abs(iLayer - 2);
266 id.resize(distance + 1);
267 std::iota(
id.begin(),
id.end(), (iCell - distance / 2) %
nCellsInLayer);
268 id.erase(std::remove_if(
id.begin(),
id.end(), [](
short i) {
271 tsMap.insert({iCell,
id});
283 vector<int> iAxialHit;
284 for (
int i = 0; i <
m_cdcHits.getEntries(); ++i) {
290 if (
m_cdcHits[i]->getISuperLayer() % 2 == 0) {
291 iAxialHit.push_back(i);
295 std::sort(iAxialHit.begin(), iAxialHit.end(), [
this](
int i,
int j) {
296 return m_cdcHits[i]->getTDCCount() > m_cdcHits[j]->getTDCCount();
304 for (
const auto& ihit : iAxialHit) {
305 B2DEBUG(20,
"sorted TDC count: " <<
m_cdcHits[ihit]->getTDCCount() <<
306 ", SL" <<
m_cdcHits[ihit]->getISuperLayer() <<
", layer" <<
m_cdcHits[ihit]->getILayer() <<
307 ", wire " <<
m_cdcHits[ihit]->getIWire() <<
", ihit: " << ihit);
317 itr->push_back(ihit);
323 for (
auto& sl : clock) {
324 for (
auto& merger : sl.second) {
333 return ! reg[field][iTS];
349 timeVec& priorityTime = (get<MergerOut::priorityTime>(mergerData))[priTS];
351 if (
notHit(MergerOut::priorityTime, priTS, registeredCell)) {
352 priorityTime = hitTime;
353 registerHit(MergerOut::priorityTime, priTS, registeredCell);
354 get<MergerOut::secondPriorityHit>(mergerData)[0].set(priTS, ! lr);
355 priorityHit.insert({priTS, iHit});
357 }
else if (
priority(priorityHit[priTS]) == Priority::second &&
358 hitTime.to_ulong() == priorityTime.to_ulong() && lr == 1) {
359 get<MergerOut::secondPriorityHit>(mergerData)[0].reset(priTS);
360 priorityHit[priTS] = iHit;
368 for (
auto& merger : sl) {
382 map<unsigned, mergerStruct<5> > dataInClock;
383 map<unsigned, registeredStruct> registered;
391 std::stable_partition(clock.begin(), clock.end(),
392 [
this](
int hit) {return priority(hit) == Priority::first;});
393 for (
const auto& iHit : clock) {
395 const unsigned short iSL = hit.getISuperLayer();
396 const short outer = (iSL == 0) ? 0 : 1;
401 auto& mergerData = dataInClock[iSL][iMerger];
402 auto& registeredCell = registered[iSL][iMerger];
405 B2DEBUG(50,
"iHit: " << iHit <<
", Merger" << iSL <<
"-" << iMerger <<
406 ", iCell: " << iCell);
408 get<MergerOut::hitmap>(mergerData)[0].set(iCell);
410 for (
const auto& iTS : tsList) {
411 timeVec& fastestTime = (get<MergerOut::fastestTime>(mergerData))[iTS];
413 if (
notHit(MergerOut::fastestTime, iTS, registeredCell) ||
415 hitTime.to_ulong() < fastestTime.to_ulong()) {
419 fastestTime = hitTime;
420 registerHit(MergerOut::fastestTime, iTS, registeredCell);
425 for (
auto& iEdgeTime :
m_edge[outer][iCell]) {
426 timeVec& edgeTime = (get<MergerOut::edgeTime>(mergerData))[iEdgeTime];
427 if (
notHit(MergerOut::edgeTime, iEdgeTime, registeredCell) ||
428 hitTime.to_ulong() < edgeTime.to_ulong()) {
430 registerHit(MergerOut::edgeTime, iEdgeTime, registeredCell);
435 case Priority::first: {
439 timeVec& priorityTime = (get<MergerOut::priorityTime>(mergerData))[priTS];
441 if (
notHit(MergerOut::priorityTime, priTS, registeredCell)) {
442 priorityTime = hitTime;
443 registerHit(MergerOut::priorityTime, priTS, registeredCell);
444 get<MergerOut::secondPriorityHit>(mergerData)[0].reset(priTS);
445 priorityHit.insert({priTS, iHit});
449 case Priority::second: {
451 for (
unsigned i = 0; i < 2; ++i) {
457 const unsigned short iMergerPlus1 = (iMerger ==
nMergers[iSL] - 1) ? 0 : iMerger + 1;
458 auto& nextMergerData = dataInClock[iSL][iMergerPlus1];
459 auto& nextRegisteredCell = registered[iSL][iMergerPlus1];
460 auto& nextPriorityHit =
m_priorityHit[iClock][iSL][iMergerPlus1];
461 setSecondPriority(priTS, iHit, hitTime, i, nextMergerData, nextRegisteredCell, nextPriorityHit);
463 setSecondPriority(priTS, iHit, hitTime, i, mergerData, registeredCell, priorityHit);
474 unsigned nEdges = (iAx == 0) ? 5 : 3;
475 for (
unsigned iMerger = 0; iMerger <
inputToTSF[iAx].size(); ++iMerger) {
476 auto input =
inputToTSF[iAx][iMerger].rbegin();
477 auto& output = dataInClock[2 * iAx][iMerger];
485 if (get<MergerOut::hitmap>(output)[0].any()) {
486 string priTime, fasTime, edgTime;
488 priTime += get<MergerOut::priorityTime>(output)[i].to_string() +
",";
489 fasTime += get<MergerOut::fastestTime>(output)[i].to_string() +
",";
490 edgTime += get<MergerOut::edgeTime>(output)[i].to_string() +
",";
491 get<MergerOut::priorityTime>(outputAcrossClocks)[i] |=
492 get<MergerOut::priorityTime>(output)[i];
493 get<MergerOut::fastestTime>(outputAcrossClocks)[i] |=
494 get<MergerOut::fastestTime>(output)[i];
496 B2DEBUG(150,
"merger " << iAx * 2 <<
"-" << iMerger <<
497 "\nhitmap: " << get<MergerOut::hitmap>(output)[0] <<
498 "\nsecond hit: " << get<MergerOut::secondPriorityHit>(output)[0] <<
499 "\nprioiry Time: " << priTime <<
500 "\nfastest Time: " << fasTime <<
501 "\nedge Time: " << edgTime);
502 get<MergerOut::hitmap>(outputAcrossClocks)[0] |= get<MergerOut::hitmap>(output)[0];
506 bitset<9> cc(iClock);
507 const int nBitsReserved = (iAx == 0) ? 3 : 4;
508 generate(
inputToTSF[iAx][iMerger].rend() - 9 - nBitsReserved,
509 inputToTSF[iAx][iMerger].rend() - nBitsReserved,
510 [&cc, i = 0]()
mutable {
517template<MergerOut field,
size_t w
idth>
518void TSF::pack(inputVector::reverse_iterator& input,
unsigned number,
521 std::generate(input, input + number * width, [&, n = 0]()
mutable {
528 return (get<field>(output)[i / width][i % width]) ?
one_val :
zero_val;
530 input += number * width;
542 const int ccWidth = 9;
544 const int widenedClocks = 16;
546 const int latency = 3;
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) {
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) {
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]);
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");
631 globalSegmentID(iTS, 2 * iAx),
658 B2INFO(
string(15,
'=') <<
" clock #" << iClock <<
" " <<
string(15,
'='));
660 cout <<
"Accumulative hitmap:" <<
"\n";
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 <<
": ";
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";
703 array<char*, m_nSubModules> rawInputToTSF = {TSF0, TSF2, TSF4, TSF6, TSF8};
706 B2DEBUG(100,
"input to TSF" << iSL * 2 <<
": \n" <<
715 B2DEBUG(50,
"Reading buffer from TSF " << iSL * 2 <<
":");
717 B2DEBUG(30,
"received TSF " << iSL * 2 <<
":");
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);
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
This class is the interface between TSim/basf2 TSF module and the firmware simulation core of XSim/IS...
std::vector< mergerStructElement< nEdges > > mergerStruct
data structure to hold merger output
int m_iFirstHit
ID of the earliest CDC hit in an event.
void initializeMerger()
Get CDC hits from the DataStore and distribute them to clocks.
static constexpr std::array< int, 9 > nMergers
number of mergers in each super layer
void computeEdges()
Compute the map from merger cell ID to all its related edge fields.
bool m_simulateCC
flag to simulate front-end clock counter
int m_TDCCountForT0
TDC count value from T0.
int m_debugLevel
debug level specified in the steering file
void saveFirmwareOutput()
save firmware output
unsigned short trgTime(int index, int iFirstHit)
Get the trigger time of the CDC hit.
Belle2::StoreArray< CDCHit > m_cdcHits
CDCHit array.
std::array< edgeList, 2 > m_edge
map from cell ID to related edge ID
std::bitset< 4 > timeStamp(int index, int iFirstHit)
Get the trigger time stamp of a hit.
std::string design_libname_post
path to the simulation snapshot
outputArray read(FILE *instream)
write TSF output signals from the worker
static constexpr int nCellsInLayer
Number of wire/cells in a single layer per merger unit.
std::array< cellList, 5 > innerInvEdge
list of cell ID related to edge timing
StoreArray< CDCTriggerSegmentHit > m_tsHits
unpacked track segment hit
std::vector< registeredStructElement > registeredStruct
vector of registeredStructElement
bool notHit(CDCTrigger::MergerOut field, unsigned iTS, registeredStructElement ®)
Whether a time field in a merger has been hit in the clock cycle.
priorityHitStruct m_priorityHit
list keeping the index of priority hit of a TS for making fastsim ts hit object
WireSet segmentID(int iHit)
Get the list of associated track segments with a hit.
void initialize() override
spawn child process for workers, open pipes to pass data
void pack(inputVector::reverse_iterator &rInput, unsigned number, mergerStructElement< 5 > &output)
Pack the merger output data structure to TSF input vector.
void event() override
Things to do for each event.
CDCTrigger::Priority priority(int index)
write TSF input signals to the worker
std::vector< short > WireSet
Wire set.
static constexpr int nTrackers
number of trackers
std::string m_outputCollectionName
Name of the StoreArray holding the found TS hits.
std::array< inputFromMerger, m_nSubModules > inputToTSFArray
input array to TSF
std::string design_libname_pre
path to the simulation snapshot
std::bitset< timeWidth > timeVec
element of data structure to hold merger output
std::array< std::array< int, 2 >, m_nSubModules > inputFileDescriptor
array holding file descriptors of pipes
static constexpr int m_nClockPerEvent
how many clocks to simulate per event
std::string m_outputBitstreamNameTo2D
Name of the StoreArray holding the raw bit content to 2D trackers.
void terminate() override
close the pipes and wait for children to die.
std::array< outputVector, nTrackers > outputArray
output array
std::array< outputArray, m_nSubModules > outputToTracker
array holding TSF output data
StoreArray< signalBitStream > m_bitsTo2D
bitstream of TSF output to 2D tracker
std::array< std::array< int, 2 >, m_nSubModules > outputFileDescriptor
array holding file descriptors of pipes
void setSecondPriority(unsigned priTS, unsigned iHit, timeVec hitTime, unsigned lr, mergerStructElement< 5 > &mergerData, registeredStructElement ®isteredCell, priorityHitInMerger &priorityHit)
set 2nd priority info
static constexpr std::array< int, m_nSubModules > nAxialMergers
number of mergers in axial super layers
std::tuple< std::array< timeVec, nSegmentsInMerger >, std::array< timeVec, nSegmentsInMerger >, std::array< timeVec, nEdges >, std::array< std::bitset< nWiresInMerger >, 1 >, std::array< std::bitset< nSegmentsInMerger >, 1 > > mergerStructElement
data structure to hold merger output <priority time (4 bits x 16), fast time (4 bits x 16),...
std::array< TSMap, 2 > m_tsMap
map from cell ID to TS ID, for inner and outer Merger
CDCTriggerTSFFirmwareModule()
Constructor.
std::string wdbName_pre
wdb name prefix
std::vector< bool > m_stubLUT
list of flags to run a TSF firmware simulation with dummy L/R LUT (to speed up loading)
char * getData(inputToTSFArray)
get the XSI compliant format from the bits format TSF input
void write(const char *message, FILE *outstream)
write TSF input signals to the worker
inputToTSFArray inputToTSF
XSI compliant format of input to TSF.
void saveFastOutput(short iclock)
save fast TSIM output
static constexpr int nSegmentsInMerger
number of track segments in a single merger unit
bool m_allPositiveTime
switch If true, the trigger time of the hit with largest TDC count becomes 0.
std::array< pid_t, m_nSubModules > m_pid
'1' in XSI VHDL simulation
static constexpr int mergerWidth
merger output data width
std::string wdbName_post
wdb name extension
static constexpr int clockPeriod
data clock period (32ns) in unit of 2ns
unsigned short mergerNumber(int index)
Get the merger unit ID in a super layer.
static constexpr int nWiresInMerger
number of wire/cell in a single merger unit
bool m_mergerOnly
flag to only simulation merger and not TSF
std::array< cellList, 3 > outerInvEdge
list of cell ID related to edge timing
std::map< unsigned, mergerStruct< 5 > > dataAcrossClocks
data structure to hold merger output
void simulateMerger(unsigned iclock)
Simulate 1 clock of merger.
std::string m_hitCollectionName
Name of the StoreArray containing the input CDC hits.
std::array< std::bitset< nCellsInLayer >, 3 > registeredStructElement
record when a time slow has been registered by a hit <priority time, fast time, edge timing>
std::unordered_map< short, WireSet > TSMap
TS map.
static constexpr int m_nSubModules
number of TSF to simulate
std::vector< priorityHitInMerger > priorityHitStructInSL
priority hits map in Merger for a SL
std::map< unsigned, int > priorityHitInMerger
priority hits map in Merger
std::array< streamPair, m_nSubModules > stream
array holding file handlers of pipes
unsigned short mergerCellID(int index)
Get the cell ID in the merger.
static constexpr int width_out
width of output data width
void registerHit(CDCTrigger::MergerOut field, unsigned iTS, registeredStructElement ®)
Register the timing field so that later hits won't overwrite it.
std::vector< std::vector< int > > iAxialHitInClock
CDC hit ID in each clock.
LogConfig & getLogConfig()
Returns the log system configuration.
void setDescription(const std::string &description)
Sets the description of the module.
Type-safe access to single objects in the data store.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.
Helper class for software (C++) / firmware (VHDL) co-simulation.
const char one_val
'1' in XSI VHDL simulation
void display_hex(const std::array< char, N > &signal)
Display signal in hex.
std::string slv_to_bin_string(std::array< char, N > signal, bool padding=false)
Transform into string.
std::string display_value(const char *count, int size)
Display value of the signal.
const char zero_val
'0' in XSI VHDL simulation