40GPUdii()
void GPUTPCCFDecodeZS::Thread<
GPUTPCCFDecodeZS::decodeZS>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer, int32_t firstHBF, int32_t tpcTimeBinCut)
42 GPUTPCCFDecodeZS::decode(clusterer, smem, nBlocks, nThreads, iBlock, iThread, firstHBF, tpcTimeBinCut);
47 const uint32_t sector = clusterer.mISector;
49 const uint32_t
endpoint = clusterer.mPzsOffsets[iBlock].endpoint;
59 const size_t nDigits = clusterer.mPzsOffsets[iBlock].offset;
62 s.nRowsRegion = GPUTPCGeometry::GetRegionRows(region);
63 s.regionStartRow = GPUTPCGeometry::GetRegionStart(region);
64 s.nThreadsPerRow = CAMath::Max(1u, nThreads / ((
s.nRowsRegion + (
endpoint & 1)) / 2));
65 s.rowStride = nThreads /
s.nThreadsPerRow;
66 s.rowOffsetCounter = 0;
69 const uint32_t myRow = iThread /
s.nThreadsPerRow;
70 const uint32_t mySequence = iThread %
s.nThreadsPerRow;
73 const uint32_t
j = clusterer.mPzsOffsets[iBlock].num;
77 for (uint32_t
i = clusterer.mMinMaxCN[
endpoint].zsPtrFirst;
i < clusterer.mMinMaxCN[
endpoint].zsPtrLast;
i++) {
78 const uint32_t minJ = (
i == clusterer.mMinMaxCN[
endpoint].zsPtrFirst) ? clusterer.mMinMaxCN[
endpoint].zsPageFirst : 0;
79 const uint32_t maxJ = (
i + 1 == clusterer.mMinMaxCN[
endpoint].zsPtrLast) ? clusterer.mMinMaxCN[
endpoint].zsPageLast : zs.nZSPtr[
endpoint][
i];
80 for (uint32_t
j = minJ;
j < maxJ;
j++) {
96 pagePtr +=
sizeof(*hdr);
97 const bool decode12bit = hdr->
version == 2;
99 const float decodeBitsFactor = 1.f / (1 << (decodeBits - 10));
100 uint32_t
mask = (1 << decodeBits) - 1;
102 const int32_t rowOffset =
s.regionStartRow + ((
endpoint & 1) ? (
s.nRowsRegion / 2) : 0);
103 const int32_t
nRows = (
endpoint & 1) ? (
s.nRowsRegion -
s.nRowsRegion / 2) : (
s.nRowsRegion / 2);
105 for (int32_t l = 0; l < hdr->nTimeBinSpan; l++) {
106 pagePtr += (pagePtr - page) & 1;
108 if ((tbHdr->
rowMask & 0x7FFF) == 0) {
112 const int32_t nRowsUsed = CAMath::Popcount((uint32_t)(tbHdr->
rowMask & 0x7FFF));
113 pagePtr += 2 * nRowsUsed;
116 for (int32_t
n = iThread;
n < nRowsUsed;
n += nThreads) {
117 const uint8_t* rowData =
n == 0 ? pagePtr : (page + tbHdr->rowAddr1()[
n - 1]);
118 s.RowClusterOffset[
n] = CAMath::AtomicAddShared<uint32_t>(&
s.rowOffsetCounter, rowData[2 * *rowData]);
138 if (myRow <
s.rowStride) {
139 for (int32_t
m = myRow;
m <
nRows;
m +=
s.rowStride) {
140 if ((tbHdr->
rowMask & (1 <<
m)) == 0) {
143 const int32_t rowPos = CAMath::Popcount((uint32_t)(tbHdr->
rowMask & ((1 <<
m) - 1)));
144 size_t nDigitsTmp = nDigits +
s.RowClusterOffset[rowPos];
145 const uint8_t* rowData = rowPos == 0 ? pagePtr : (page + tbHdr->rowAddr1()[rowPos - 1]);
146 const int32_t nSeqRead = *rowData;
147 const int32_t nSeqPerThread = (nSeqRead +
s.nThreadsPerRow - 1) /
s.nThreadsPerRow;
148 const int32_t mySequenceStart = mySequence * nSeqPerThread;
149 const int32_t mySequenceEnd = CAMath::Min(mySequenceStart + nSeqPerThread, nSeqRead);
150 if (mySequenceEnd > mySequenceStart) {
151 const uint8_t* adcData = rowData + 2 * nSeqRead + 1;
152 const uint32_t nSamplesStart = mySequenceStart ? rowData[2 * mySequenceStart] : 0;
153 nDigitsTmp += nSamplesStart;
154 uint32_t nADCStartBits = nSamplesStart * decodeBits;
155 const uint32_t nADCStart = (nADCStartBits + 7) / 8;
156 const int32_t nADC = (rowData[2 * mySequenceEnd] * decodeBits + 7) / 8;
157 adcData += nADCStart;
158 nADCStartBits &= 0x7;
159 uint32_t
byte = 0,
bits = 0;
161 bits = 8 - nADCStartBits;
162 byte = ((*(adcData - 1) & (0xFF ^ ((1 << nADCStartBits) - 1)))) >> nADCStartBits;
164 int32_t nSeq = mySequenceStart;
165 int32_t seqLen = nSeq ? (rowData[(nSeq + 1) * 2] - rowData[nSeq * 2]) : rowData[2];
166 Pad pad = rowData[nSeq++ * 2 + 1];
167 for (int32_t
n = nADCStart;
n < nADC;
n++) {
168 byte |= *(adcData++) <<
bits;
170 while (
bits >= decodeBits) {
172 seqLen = rowData[(nSeq + 1) * 2] - rowData[nSeq * 2];
173 pad = rowData[nSeq++ * 2 + 1];
175 const CfFragment& fragment = clusterer.mPmemory->fragment;
176 TPCTime globalTime = timeBin + l;
177 bool discardTimeBin = not fragment.contains(globalTime);
178 discardTimeBin |= (tpcTimeBinCut > 0 && globalTime > tpcTimeBinCut);
182 positions[nDigitsTmp++] =
pos;
184 if (!discardTimeBin) {
185 float q = float(
byte &
mask) * decodeBitsFactor;
186 q *= clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(sector,
row, pad);
190 byte =
byte >> decodeBits;
199 pagePtr = page + tbHdr->rowAddr1()[nRowsUsed - 2];
201 pagePtr += 2 * *pagePtr;
202 pagePtr += 1 + (*pagePtr * decodeBits + 7) / 8;
215GPUdii()
void GPUTPCCFDecodeZSLink::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer, int32_t firstHBF, int32_t tpcTimeBinCut)
217 Decode<GPUTPCCFDecodeZSLink>(nBlocks, nThreads, iBlock, iThread, smem, clusterer, firstHBF, tpcTimeBinCut);
222 const CfFragment& fragment = ctx.clusterer.mPmemory->fragment;
224 const auto* rdHdr = ConsumeHeader<header::RAWDataHeader>(ctx.page);
227 return ctx.pageDigitOffset;
230 [[maybe_unused]] int32_t nDecoded = 0;
231 const auto* decHdr = ConsumeHeader<TPCZSHDRV2>(ctx.page);
232 ConsumeBytes(ctx.page, decHdr->firstZSDataOffset * 16);
237 for (uint32_t t = 0; t < decHdr->nTimebinHeaders; t++) {
238 const auto* tbHdr = ConsumeHeader<zerosupp_link_based::CommonHeader>(ctx.page);
239 const auto* adcData = ConsumeBytes(ctx.page, tbHdr->numWordsPayload * 16);
243 uint32_t channelMask[3];
244 GetChannelBitmask(*tbHdr, channelMask);
245 uint32_t nAdc = CAMath::Popcount(channelMask[0]) + CAMath::Popcount(channelMask[1]) + CAMath::Popcount(channelMask[2]);
249 bool discardTimeBin = not fragment.contains(timeBin);
250 discardTimeBin |= (ctx.tpcTimeBinCut > 0 && timeBin > ctx.tpcTimeBinCut);
252 if (discardTimeBin) {
253 FillWithInvalid(ctx.clusterer, ctx.iThread, ctx.nThreads, ctx.pageDigitOffset, nAdc);
263 tbHdr->fecInPartition);
266 ctx.pageDigitOffset += nAdc;
269#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
270 if (iThread == 0 && nDecoded != decHdr->nADCsamples) {
271 clusterer.raiseError(GPUErrors::ERROR_TPCZS_INVALID_NADC, clusterer.mISector * 1000 + decHdr->cruID, decHdr->nADCsamples, nDecoded);
280 return ctx.pageDigitOffset;
284 GPUSharedMemory& smem,
286 const uint8_t* adcData,
288 const uint32_t* channelMask,
291 int32_t fecInPartition)
294 static_assert(NTHREADS == GPUCA_WARP_SIZE,
"Decoding TB Headers in parallel assumes block size is a single warp.");
297 for (uint8_t
i = ctx.iThread; blockOffset < nAdc;
i += NTHREADS) {
301 uint8_t myChannelActive = ChannelIsActive(channelMask, rawFECChannel);
303 uint8_t myOffset = warp_scan_inclusive_add(myChannelActive) - 1 + blockOffset;
304 blockOffset = warp_broadcast(myOffset, NTHREADS - 1) + 1;
306 if (not myChannelActive) {
309 assert(myOffset < nAdc);
315 uint32_t adcBitOffset = myOffset * DECODE_BITS;
316 uint32_t adcByteOffset = adcBitOffset / CHAR_BIT;
317 uint32_t adcOffsetInByte = adcBitOffset - adcByteOffset * CHAR_BIT;
319 uint32_t
byte = 0,
bits = 0;
321 while (
bits < DECODE_BITS) {
322 byte |= ((uint32_t)adcData[adcByteOffset]) <<
bits;
326 adc =
byte >> adcOffsetInByte;
329 const uint64_t* adcData64 = (
const uint64_t*)adcData;
333 o2::tpc::PadPos padAndRow = GetPadAndRowFromFEC(ctx.clusterer, cru, rawFECChannel, fecInPartition);
334 const CfFragment& fragment = ctx.clusterer.mPmemory->fragment;
335 float charge = ADCToFloat(
adc, DECODE_MASK, DECODE_BITS_FACTOR);
336 WriteCharge(ctx.clusterer,
charge, padAndRow, fragment.toLocal(timeBin), ctx.pageDigitOffset + myOffset);
343 chan[0] = tbHdr.bitMaskLow & 0xfffffffful;
344 chan[1] = tbHdr.bitMaskLow >> (
sizeof(uint32_t) * CHAR_BIT);
345 chan[2] = tbHdr.bitMaskHigh;
350 if (chanIndex >= zerosupp_link_based::ChannelPerTBHeader) {
353 constexpr uint8_t N_BITS_PER_ENTRY =
sizeof(*chan) * CHAR_BIT;
354 const uint8_t entryIndex = chanIndex / N_BITS_PER_ENTRY;
355 const uint8_t bitInEntry = chanIndex % N_BITS_PER_ENTRY;
356 return chan[entryIndex] & (1 << bitInEntry);
365template <
class Decoder>
366GPUd()
void GPUTPCCFDecodeZSLinkBase::Decode(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, typename Decoder::GPUSharedMemory& smem, processorType& clusterer, int32_t firstHBF, int32_t tpcTimeBinCut)
368 const uint32_t sector = clusterer.mISector;
371 const uint32_t
endpoint = clusterer.mPzsOffsets[iBlock].endpoint;
381 uint32_t pageDigitOffset = clusterer.mPzsOffsets[iBlock].offset;
384 const uint32_t
i = 0;
385 const uint32_t
j = clusterer.mPzsOffsets[iBlock].num;
389 for (uint32_t
i = clusterer.mMinMaxCN[
endpoint].zsPtrFirst;
i < clusterer.mMinMaxCN[
endpoint].zsPtrLast;
i++) {
390 const uint32_t minJ = (
i == clusterer.mMinMaxCN[
endpoint].zsPtrFirst) ? clusterer.mMinMaxCN[
endpoint].zsPageFirst : 0;
392 for (uint32_t
j = minJ;
j < maxJ;
j++) {
399 const uint8_t* page = (
const uint8_t*)pageSrc;
401 const auto* rdHdr = Peek<header::RAWDataHeader>(page);
412 .clusterer = clusterer,
415 .nThreads = nThreads,
417 .pageDigitOffset = pageDigitOffset,
418 .firstHBF = firstHBF,
419 .tpcTimeBinCut = tpcTimeBinCut,
422 pageDigitOffset = Decoder::DecodePage(smem, ctx);
426#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
427 if (iThread == 0 && iBlock < nBlocks - 1) {
428 uint32_t maxOffset = clusterer.mPzsOffsets[iBlock + 1].offset;
429 if (pageDigitOffset != maxOffset) {
430 clusterer.raiseError(GPUErrors::ERROR_TPCZS_INVALID_OFFSET, clusterer.mISector * 1000 +
endpoint, pageDigitOffset, maxOffset);
436GPUd()
o2::tpc::PadPos GPUTPCCFDecodeZSLinkBase::GetPadAndRowFromFEC(processorType& clusterer, int32_t cru, int32_t rawFECChannel, int32_t fecInPartition)
438#ifdef GPUCA_TPC_GEOMETRY_O2
442 const int32_t regionIter = cru % 2;
443 const int32_t istreamm = ((rawFECChannel % 10) / 2);
444 const int32_t partitionStream = istreamm + regionIter * 5;
445 const int32_t sampaOnFEC = geo.GetSampaMapping(partitionStream);
446 const int32_t channel = (rawFECChannel % 2) + 2 * (rawFECChannel / 10);
447 const int32_t channelOnSAMPA = channel + geo.GetChannelOffset(partitionStream);
449 const int32_t partition = (cru % 10) / 2;
450 const int32_t fecInSector = geo.GetSectorFECOffset(partition) + fecInPartition;
453 assert(gpuMapping !=
nullptr);
455 uint16_t globalSAMPAId = (
static_cast<uint16_t
>(fecInSector) << 8) + (
static_cast<uint16_t
>(sampaOnFEC) << 5) +
static_cast<uint16_t
>(channelOnSAMPA);
464GPUd()
void GPUTPCCFDecodeZSLinkBase::WriteCharge(processorType& clusterer,
float charge,
PadPos padAndRow,
TPCFragmentTime localTime,
size_t positionOffset)
468#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
480 charge *=
clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(sector, padAndRow.getRow(), padAndRow.getPad());
485GPUd() uint16_t GPUTPCCFDecodeZSLinkBase::FillWithInvalid(processorType& clusterer, int32_t iThread, int32_t nThreads, uint32_t pageDigitOffset, uint16_t nSamples)
500GPUd()
void GPUTPCCFDecodeZSDenseLink::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer, int32_t firstHBF, int32_t tpcTimeBinCut)
502 Decode<GPUTPCCFDecodeZSDenseLink>(nBlocks, nThreads, iBlock, iThread, smem, clusterer, firstHBF, tpcTimeBinCut);
507 const uint8_t*
const pageStart = ctx.page;
509 const auto* rawDataHeader = Peek<header::RAWDataHeader>(ctx.page);
510 const auto* decHeader = Peek<TPCZSHDRV2>(ctx.page, raw::RDHUtils::getMemorySize(*rawDataHeader) -
sizeof(
TPCZSHDRV2));
511 ConsumeHeader<header::RAWDataHeader>(ctx.page);
513 uint16_t nSamplesWritten = 0;
514 const uint16_t nSamplesInPage = decHeader->nADCsamples;
516 const auto* payloadEnd = Peek(pageStart, raw::RDHUtils::getMemorySize(*rawDataHeader) -
sizeof(
TPCZSHDRV2) - ((decHeader->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent) ?
TPCZSHDRV2::TRIGGER_WORD_SIZE : 0));
519 const bool extendsToNextPage = decHeader->flags & TPCZSHDRV2::ZSFlags::payloadExtendsToNextPage;
523 int err = GPUErrors::ERROR_NONE;
526 err = GPUErrors::ERROR_TPCZS_VERSION_MISMATCH;
530 err = GPUErrors::ERROR_TPCZS_INVALID_MAGIC_WORD;
533 for (uint16_t
i = 0;
i < decHeader->nTimebinHeaders && !err;
i++) {
535 ptrdiff_t sizeLeftInPage = payloadEnd - ctx.page;
536 if (sizeLeftInPage <= 0) {
537 err = GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW;
541 int16_t nSamplesWrittenTB = 0;
542 uint16_t nSamplesLeftInPage = nSamplesInPage - nSamplesWritten;
544 if (
i == decHeader->nTimebinHeaders - 1 && extendsToNextPage) {
546 err = GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW;
550 if ((uint16_t)(raw::RDHUtils::getPageCounter(rawDataHeader) + 1) == raw::RDHUtils::getPageCounter(nextPage)) {
551 nSamplesWrittenTB = DecodeTB<true>(smem, ctx, rawDataHeader, decHeader->cruID, nSamplesLeftInPage, payloadEnd, nextPage);
553 err = GPUErrors::ERROR_TPCZS_INCOMPLETE_HBF;
557 nSamplesWrittenTB = DecodeTB<false>(smem, ctx, rawDataHeader, decHeader->cruID, nSamplesLeftInPage, payloadEnd, nextPage);
561 if (nSamplesWrittenTB < 0) {
562 err = -nSamplesWrittenTB;
566 nSamplesWritten += nSamplesWrittenTB;
567 ctx.pageDigitOffset += nSamplesWrittenTB;
570 if (nSamplesWritten != nSamplesInPage) {
571 if (nSamplesWritten < nSamplesInPage) {
572 ctx.pageDigitOffset += FillWithInvalid(ctx.clusterer, ctx.iThread, ctx.nThreads, ctx.pageDigitOffset, nSamplesInPage - nSamplesWritten);
574 err = !err ? GPUErrors::ERROR_TPCZS_INVALID_NADC : err;
577 if (ctx.iThread == 0 && err) {
578 [[maybe_unused]]
bool dumpPage =
false;
580 if (err == GPUErrors::ERROR_TPCZS_VERSION_MISMATCH) {
582 }
else if (err == GPUErrors::ERROR_TPCZS_INVALID_MAGIC_WORD) {
583 ctx.clusterer.raiseError(err, decHeader->magicWord);
584 }
else if (err == GPUErrors::ERROR_TPCZS_INCOMPLETE_HBF) {
585 ctx.clusterer.raiseError(err, ctx.clusterer.mISector * 1000 + decHeader->cruID, raw::RDHUtils::getPageCounter(rawDataHeader), raw::RDHUtils::getPageCounter(nextPage));
586 }
else if (err == GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW) {
587 ctx.clusterer.raiseError(err, extendsToNextPage);
589 }
else if (err == GPUErrors::ERROR_TPCZS_INVALID_NADC) {
590 ctx.clusterer.raiseError(err, nSamplesInPage, nSamplesWritten, extendsToNextPage);
593 ctx.clusterer.raiseError(GPUErrors::ERROR_TPCZS_UNKNOWN, err);
596#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
600 const char fname[64] =
"dump00.bin";
601 FILE*
foo = fopen(fname,
"w+b");
609 return ctx.pageDigitOffset;
612template <
bool PayloadExtendsToNextPage>
614 GPUSharedMemory& smem,
616 const header::RAWDataHeader* rawDataHeader,
618 uint16_t nSamplesLeftInPage,
619 const uint8_t* payloadEnd,
620 const uint8_t* nextPage)
622#define MAYBE_PAGE_OVERFLOW(pagePtr) \
623 if constexpr (PayloadExtendsToNextPage) { \
624 if (pagePtr >= payloadEnd && pagePtr < nextPage) { \
625 ptrdiff_t diff = pagePtr - payloadEnd; \
626 pagePtr = nextPage; \
627 ConsumeBytes(pagePtr, sizeof(header::RAWDataHeader) + diff); \
630 if (pagePtr > payloadEnd) { \
631 return -GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW; \
635#define PEEK_OVERFLOW(pagePtr, offset) \
636 (*(PayloadExtendsToNextPage && (pagePtr) < nextPage && (pagePtr) + (offset) >= payloadEnd \
637 ? nextPage + sizeof(header::RAWDataHeader) + ((pagePtr) + (offset) - payloadEnd) \
638 : (pagePtr) + (offset)))
640#define TEST_BIT(x, bit) static_cast<bool>((x) & (1 << (bit)))
643 static_assert(NTHREADS == GPUCA_WARP_SIZE,
"Decoding TB Headers in parallel assumes block size is a single warp.");
645 const CfFragment& fragment = ctx.clusterer.mPmemory->fragment;
648 uint16_t tbbHdr = ConsumeByte(ctx.page);
650 tbbHdr |=
static_cast<uint16_t
>(ConsumeByte(ctx.page)) << CHAR_BIT;
653 uint8_t nLinksInTimebin = tbbHdr & 0x000F;
654 uint16_t linkBC = (tbbHdr & 0xFFF0) >> 4;
657 int16_t nSamplesInTB = 0;
660 for (uint8_t iLink = 0; iLink < nLinksInTimebin; iLink++) {
661 uint8_t timebinLinkHeaderStart = ConsumeByte(ctx.page);
664 if (ctx.iThread == 0) {
665 smem.linkIds[iLink] = timebinLinkHeaderStart & 0b00011111;
667 bool bitmaskIsFlat = timebinLinkHeaderStart & 0b00100000;
669 uint16_t bitmaskL2 = 0x03FF;
670 if (not bitmaskIsFlat) {
671 bitmaskL2 =
static_cast<uint16_t
>(timebinLinkHeaderStart & 0b11000000) << 2 |
static_cast<uint16_t
>(ConsumeByte(ctx.page));
675 int32_t nBytesBitmask = CAMath::Popcount(bitmaskL2);
677 for (int32_t chan = ctx.iThread; chan < CAMath::nextMultipleOf<NTHREADS>(80); chan += NTHREADS) {
678 int32_t chanL2Idx = chan / 8;
679 bool l2 =
TEST_BIT(bitmaskL2, chanL2Idx);
681 int32_t chanByteOffset = nBytesBitmask - 1 - CAMath::Popcount(bitmaskL2 >> (chanL2Idx + 1));
685 int32_t nSamplesStep;
686 int32_t threadSampleOffset = CfUtils::warpPredicateScan(myChannelHasData, &nSamplesStep);
688 if (myChannelHasData) {
689 smem.rawFECChannels[nSamplesInTB + threadSampleOffset] = chan;
692 nSamplesInTB += nSamplesStep;
695 ConsumeBytes(ctx.page, nBytesBitmask);
698 if (ctx.iThread == 0) {
699 smem.samplesPerLinkEnd[iLink] = nSamplesInTB;
706 if (nSamplesInTB > nSamplesLeftInPage) {
707 return -GPUErrors::ERROR_TPCZS_INVALID_NADC;
712 const uint8_t* adcData = ConsumeBytes(ctx.page, (nSamplesInTB * DECODE_BITS + 7) / 8);
715 bool discardTimeBin = not fragment.contains(timeBin);
716 discardTimeBin |= (ctx.tpcTimeBinCut > 0 && timeBin > ctx.tpcTimeBinCut);
718 if (discardTimeBin) {
719 return FillWithInvalid(ctx.clusterer, ctx.iThread, NTHREADS, ctx.pageDigitOffset, nSamplesInTB);
724 for (uint16_t sample = ctx.iThread; sample < nSamplesInTB; sample += NTHREADS) {
725 const uint16_t adcBitOffset = sample * DECODE_BITS;
726 uint16_t adcByteOffset = adcBitOffset / CHAR_BIT;
727 const uint8_t adcOffsetInByte = adcBitOffset - adcByteOffset * CHAR_BIT;
729 static_assert(DECODE_BITS <=
sizeof(uint16_t) * CHAR_BIT);
732 for (uint8_t
bits = 0;
bits < DECODE_BITS;
bits += CHAR_BIT) {
736 adc >>= adcOffsetInByte;
738 while (smem.samplesPerLinkEnd[iLink] <= sample) {
742 int32_t rawFECChannelLink = smem.rawFECChannels[sample];
745 o2::tpc::PadPos padAndRow = GetPadAndRowFromFEC(ctx.clusterer, cru, rawFECChannelLink, smem.linkIds[iLink]);
747 float charge = ADCToFloat(
adc, DECODE_MASK, DECODE_BITS_FACTOR);
748 WriteCharge(ctx.clusterer,
charge, padAndRow, fragment.toLocal(timeBin), ctx.pageDigitOffset + sample);
758#undef MAYBE_PAGE_OVERFLOW
763 constexpr uint8_t N_BITS_PER_ENTRY =
sizeof(*chan) * CHAR_BIT;
764 const uint8_t entryIndex = chanIndex / N_BITS_PER_ENTRY;
765 const uint8_t bitInEntry = chanIndex % N_BITS_PER_ENTRY;
766 return chan[entryIndex] & (1 << bitInEntry);
#define GPUCA_GET_THREAD_COUNT(...)
#define CA_SHARED_CACHE_REF(target, src, size, reftype, ref)
GPUdii() void GPUTPCCFDecodeZS
#define MAYBE_PAGE_OVERFLOW(pagePtr)
#define PEEK_OVERFLOW(pagePtr, offset)
Header to collect LHC related constants.
GPUd() static o2 float o2::tpc::PadPos tpccf::TPCFragmentTime localTime
GPUd() static o2 float o2::tpc::PadPos pos
int32_t int32_t int32_t Decoder::GPUSharedMemory processorType & clusterer
GPUd() static o2 float charge
int32_t int32_t uint32_t pageDigitOffset
GPUd() static o2 float o2::tpc::PadPos tpccf::TPCFragmentTime size_t positionOffset
int32_t int32_t uint32_t uint16_t nSamples
int32_t int32_t int32_t iThread
CfChargePos * mPpositions
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
uint8_t itsSharedClusterMap uint8_t
constexpr int LHCMaxBunches
constexpr CfChargePos INVALID_CHARGE_POS
GPUd() const expr uint32_t MultivariatePolynomialHelper< Dim
constexpr int LHCBCPERTIMEBIN
Global TPC definitions and constants.
@ ZSVersionDenseLinkBased
@ ZSVersionLinkBasedWithMeta
constexpr std::array< int, nLayers > nRows
const void *const * zsPtr[NENDPOINTS]
uint32_t count[NENDPOINTS]
const uint32_t * nZSPtr[NENDPOINTS]
static constexpr bool TIGHTLY_PACKED_V3
static constexpr unsigned int SAMPLESPER64BIT
static constexpr unsigned int TRIGGER_WORD_SIZE
static constexpr unsigned int TPC_ZS_NBITS_V1
static constexpr unsigned int TPC_ZS_NBITS_V2
static constexpr size_t TPC_ZS_PAGE_SIZE
coder decode(ctfImage, triggersD, clustersD)