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;
51 const bool deviceLayout = clusterer.IsDeviceProcessor();
52 const uint32_t
endpoint = deviceLayout ? clusterer.mPzsOffsets[iBlock].endpoint : iBlock;
60 const size_t nDigits = clusterer.mPzsOffsets[iBlock].offset;
63 s.nRowsRegion = GPUTPCGeometry::GetRegionRows(region);
64 s.regionStartRow = GPUTPCGeometry::GetRegionStart(region);
65 s.nThreadsPerRow = CAMath::Max(1u, nThreads / ((
s.nRowsRegion + (
endpoint & 1)) / 2));
66 s.rowStride = nThreads /
s.nThreadsPerRow;
67 s.rowOffsetCounter = 0;
70 const uint32_t myRow = iThread /
s.nThreadsPerRow;
71 const uint32_t mySequence = iThread %
s.nThreadsPerRow;
74 const uint32_t
j = clusterer.mPzsOffsets[iBlock].num;
78 const uint32_t iFirst = deviceLayout ? 0 : clusterer.mMinMaxCN[
endpoint].zsPtrFirst;
79 const uint32_t iLast = deviceLayout ? 1 : clusterer.mMinMaxCN[
endpoint].zsPtrLast;
80 for (uint32_t
i = iFirst;
i < iLast;
i++) {
81 const uint32_t minJ = deviceLayout ? clusterer.mPzsOffsets[iBlock].num : ((
i == iFirst) ? clusterer.mMinMaxCN[
endpoint].zsPageFirst : 0);
82 const uint32_t maxJ = deviceLayout ? (minJ + 1) : ((
i + 1 == iLast) ? clusterer.mMinMaxCN[
endpoint].zsPageLast : zs.nZSPtr[
endpoint][
i]);
83 for (uint32_t
j = minJ;
j < maxJ;
j++) {
85 const uint32_t* pageSrc = (
const uint32_t*)(((
const uint8_t*)zs.
zsPtr[
endpoint][
i]) +
j * TPCZSHDR::TPC_ZS_PAGE_SIZE);
101 const uint32_t decodeBits = decode12bit ? TPCZSHDR::TPC_ZS_NBITS_V2 : TPCZSHDR::TPC_ZS_NBITS_V1;
102 const float decodeBitsFactor = 1.f / (1 << (decodeBits - 10));
103 uint32_t
mask = (1 << decodeBits) - 1;
104 int32_t timeBin = (
hdr->
timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN;
105 const int32_t rowOffset =
s.regionStartRow + ((
endpoint & 1) ? (
s.nRowsRegion / 2) : 0);
106 const int32_t
nRows = (
endpoint & 1) ? (
s.nRowsRegion -
s.nRowsRegion / 2) : (
s.nRowsRegion / 2);
111 if ((tbHdr->
rowMask & 0x7FFF) == 0) {
115 const int32_t nRowsUsed = CAMath::Popcount((uint32_t)(tbHdr->
rowMask & 0x7FFF));
119 for (int32_t
n = iThread;
n < nRowsUsed;
n += nThreads) {
121 s.RowClusterOffset[
n] = CAMath::AtomicAddShared<uint32_t>(&
s.rowOffsetCounter, rowData[2 * *rowData]);
141 if (myRow <
s.rowStride) {
142 for (int32_t
m = myRow;
m <
nRows;
m +=
s.rowStride) {
143 if ((tbHdr->
rowMask & (1 <<
m)) == 0) {
146 const int32_t rowPos = CAMath::Popcount((uint32_t)(tbHdr->
rowMask & ((1 <<
m) - 1)));
147 size_t nDigitsTmp = nDigits +
s.RowClusterOffset[rowPos];
148 const uint8_t* rowData = rowPos == 0 ?
pagePtr : (
page + tbHdr->rowAddr1()[rowPos - 1]);
149 const int32_t nSeqRead = *rowData;
150 const int32_t nSeqPerThread = (nSeqRead +
s.nThreadsPerRow - 1) /
s.nThreadsPerRow;
151 const int32_t mySequenceStart = mySequence * nSeqPerThread;
152 const int32_t mySequenceEnd = CAMath::Min(mySequenceStart + nSeqPerThread, nSeqRead);
153 if (mySequenceEnd > mySequenceStart) {
154 const uint8_t* adcData = rowData + 2 * nSeqRead + 1;
155 const uint32_t nSamplesStart = mySequenceStart ? rowData[2 * mySequenceStart] : 0;
156 nDigitsTmp += nSamplesStart;
157 uint32_t nADCStartBits = nSamplesStart * decodeBits;
158 const uint32_t nADCStart = (nADCStartBits + 7) / 8;
159 const int32_t nADC = (rowData[2 * mySequenceEnd] * decodeBits + 7) / 8;
160 adcData += nADCStart;
161 nADCStartBits &= 0x7;
162 uint32_t
byte = 0,
bits = 0;
164 bits = 8 - nADCStartBits;
165 byte = ((*(adcData - 1) & (0xFF ^ ((1 << nADCStartBits) - 1)))) >> nADCStartBits;
167 int32_t
nSeq = mySequenceStart;
169 Pad pad = rowData[
nSeq++ * 2 + 1];
170 for (int32_t
n = nADCStart;
n < nADC;
n++) {
171 byte |= *(adcData++) <<
bits;
173 while (
bits >= decodeBits) {
176 pad = rowData[
nSeq++ * 2 + 1];
178 const CfFragment& frag = clusterer.mPmemory->frag;
179 TPCTime globalTime = timeBin + l;
180 bool discardTimeBin = not frag.contains(globalTime);
181 discardTimeBin |= (tpcTimeBinCut > 0 && globalTime > tpcTimeBinCut);
185 positions[nDigitsTmp++] =
pos;
187 if (!discardTimeBin) {
188 float q = float(
byte &
mask) * decodeBitsFactor;
189 q *= clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(sector,
row, pad);
193 byte =
byte >> decodeBits;
218GPUdii()
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)
220 Decode<GPUTPCCFDecodeZSLink>(nBlocks, nThreads, iBlock, iThread, smem, clusterer, firstHBF, tpcTimeBinCut);
225 const CfFragment& frag = ctx.clusterer.mPmemory->frag;
227 const auto* rdHdr = ConsumeHeader<header::RAWDataHeader>(ctx.page);
230 return ctx.pageDigitOffset;
233 [[maybe_unused]] int32_t nDecoded = 0;
234 const auto* decHdr = ConsumeHeader<TPCZSHDRV2>(ctx.page);
235 ConsumeBytes(ctx.page, decHdr->firstZSDataOffset * 16);
238 assert(decHdr->magicWord == o2::tpc::zerosupp_link_based::CommonHeader::MagicWordLinkZSMetaHeader);
240 for (uint32_t t = 0; t < decHdr->nTimebinHeaders; t++) {
241 const auto* tbHdr = ConsumeHeader<zerosupp_link_based::CommonHeader>(ctx.page);
242 const auto* adcData = ConsumeBytes(ctx.page, tbHdr->numWordsPayload * 16);
244 int32_t timeBin = (decHdr->timeOffset + tbHdr->bunchCrossing + (uint64_t)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdHdr) - ctx.firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN;
246 uint32_t channelMask[3];
247 GetChannelBitmask(*tbHdr, channelMask);
248 uint32_t nAdc = CAMath::Popcount(channelMask[0]) + CAMath::Popcount(channelMask[1]) + CAMath::Popcount(channelMask[2]);
252 bool discardTimeBin = not frag.contains(timeBin);
253 discardTimeBin |= (ctx.tpcTimeBinCut > 0 && timeBin > ctx.tpcTimeBinCut);
255 if (discardTimeBin) {
256 FillWithInvalid(ctx.clusterer, ctx.iThread, ctx.nThreads, ctx.pageDigitOffset, nAdc);
266 tbHdr->fecInPartition);
269 ctx.pageDigitOffset += nAdc;
272#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
273 if (iThread == 0 && nDecoded != decHdr->nADCsamples) {
274 clusterer.raiseError(GPUErrors::ERROR_TPCZS_INVALID_NADC, clusterer.mISector * 1000 + decHdr->cruID, decHdr->nADCsamples, nDecoded);
283 return ctx.pageDigitOffset;
287 GPUSharedMemory& smem,
289 const uint8_t* adcData,
291 const uint32_t* channelMask,
294 int32_t fecInPartition)
297 static_assert(NTHREADS == GPUCA_WARP_SIZE,
"Decoding TB Headers in parallel assumes block size is a single warp.");
300 for (uint8_t
i =
ctx.iThread; blockOffset < nAdc;
i += NTHREADS) {
304 uint8_t myChannelActive = ChannelIsActive(channelMask, rawFECChannel);
306 uint8_t myOffset = warp_scan_inclusive_add(myChannelActive) - 1 + blockOffset;
307 blockOffset = warp_broadcast(myOffset, NTHREADS - 1) + 1;
309 if (not myChannelActive) {
312 assert(myOffset < nAdc);
316 if constexpr (TPCZSHDRV2::TIGHTLY_PACKED_V3) {
318 uint32_t adcBitOffset = myOffset * DECODE_BITS;
319 uint32_t adcByteOffset = adcBitOffset / CHAR_BIT;
320 uint32_t adcOffsetInByte = adcBitOffset - adcByteOffset * CHAR_BIT;
322 uint32_t
byte = 0,
bits = 0;
324 while (
bits < DECODE_BITS) {
325 byte |= ((uint32_t)adcData[adcByteOffset]) <<
bits;
329 adc =
byte >> adcOffsetInByte;
332 const uint64_t* adcData64 = (
const uint64_t*)adcData;
333 adc = (adcData64[myOffset / TPCZSHDRV2::SAMPLESPER64BIT] >> ((myOffset % TPCZSHDRV2::SAMPLESPER64BIT) * DECODE_BITS)) & DECODE_MASK;
336 o2::tpc::PadPos padAndRow = GetPadAndRowFromFEC(
ctx.clusterer, cru, rawFECChannel, fecInPartition);
338 float charge = ADCToFloat(
adc, DECODE_MASK, DECODE_BITS_FACTOR);
339 WriteCharge(
ctx.clusterer,
charge, padAndRow, frag.toLocal(timeBin),
ctx.pageDigitOffset + myOffset);
346 chan[0] = tbHdr.bitMaskLow & 0xfffffffful;
347 chan[1] = tbHdr.bitMaskLow >> (
sizeof(uint32_t) * CHAR_BIT);
348 chan[2] = tbHdr.bitMaskHigh;
353 if (chanIndex >= zerosupp_link_based::ChannelPerTBHeader) {
356 constexpr uint8_t N_BITS_PER_ENTRY =
sizeof(*chan) * CHAR_BIT;
357 const uint8_t entryIndex = chanIndex / N_BITS_PER_ENTRY;
358 const uint8_t bitInEntry = chanIndex % N_BITS_PER_ENTRY;
359 return chan[entryIndex] & (1 << bitInEntry);
368template <
class Decoder>
369GPUd()
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)
371 const uint32_t sector = clusterer.mISector;
374 const uint32_t
endpoint = clusterer.mPzsOffsets[iBlock].endpoint;
376 const bool deviceLayout = clusterer.IsDeviceProcessor();
377 const uint32_t
endpoint = deviceLayout ? clusterer.mPzsOffsets[iBlock].endpoint : iBlock;
385 uint32_t pageDigitOffset = clusterer.mPzsOffsets[iBlock].offset;
388 const uint32_t
i = 0;
389 const uint32_t
j = clusterer.mPzsOffsets[iBlock].num;
393 const uint32_t iFirst = deviceLayout ? 0 : clusterer.mMinMaxCN[
endpoint].zsPtrFirst;
394 const uint32_t iLast = deviceLayout ? 1 : clusterer.mMinMaxCN[
endpoint].zsPtrLast;
395 for (uint32_t
i = iFirst;
i < iLast;
i++) {
396 const uint32_t minJ = deviceLayout ? clusterer.mPzsOffsets[iBlock].num : ((
i == iFirst) ? clusterer.mMinMaxCN[
endpoint].zsPageFirst : 0);
397 const uint32_t maxJ = deviceLayout ? (minJ + 1) : ((
i + 1 == iLast) ? clusterer.mMinMaxCN[
endpoint].zsPageLast : zs.
nZSPtr[
endpoint][
i]);
398 for (uint32_t
j = minJ;
j < maxJ;
j++) {
400 const uint32_t* pageSrc = (
const uint32_t*)(((
const uint8_t*)zs.
zsPtr[
endpoint][
i]) +
j * TPCZSHDR::TPC_ZS_PAGE_SIZE);
405 const uint8_t*
page = (
const uint8_t*)pageSrc;
407 const auto* rdHdr = Peek<header::RAWDataHeader>(
page);
418 .clusterer = clusterer,
421 .nThreads = nThreads,
423 .pageDigitOffset = pageDigitOffset,
424 .firstHBF = firstHBF,
425 .tpcTimeBinCut = tpcTimeBinCut,
428 pageDigitOffset = Decoder::DecodePage(smem, ctx);
432#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
433 if (iThread == 0 && iBlock < nBlocks - 1) {
434 uint32_t maxOffset = clusterer.mPzsOffsets[iBlock + 1].offset;
435 if (pageDigitOffset != maxOffset) {
436 clusterer.raiseError(GPUErrors::ERROR_TPCZS_INVALID_OFFSET, clusterer.mISector * 1000 +
endpoint, pageDigitOffset, maxOffset);
442GPUd()
o2::tpc::PadPos GPUTPCCFDecodeZSLinkBase::GetPadAndRowFromFEC(processorType& clusterer, int32_t cru, int32_t rawFECChannel, int32_t fecInPartition)
448 const int32_t regionIter = cru % 2;
449 const int32_t istreamm = ((rawFECChannel % 10) / 2);
450 const int32_t partitionStream = istreamm + regionIter * 5;
451 const int32_t sampaOnFEC = geo.GetSampaMapping(partitionStream);
452 const int32_t channel = (rawFECChannel % 2) + 2 * (rawFECChannel / 10);
453 const int32_t channelOnSAMPA = channel + geo.GetChannelOffset(partitionStream);
455 const int32_t partition = (cru % 10) / 2;
456 const int32_t fecInSector = geo.GetSectorFECOffset(partition) + fecInPartition;
459 assert(gpuMapping !=
nullptr);
461 uint16_t globalSAMPAId = (
static_cast<uint16_t
>(fecInSector) << 8) + (
static_cast<uint16_t
>(sampaOnFEC) << 5) +
static_cast<uint16_t
>(channelOnSAMPA);
470GPUd()
void GPUTPCCFDecodeZSLinkBase::WriteCharge(processorType& clusterer,
float charge,
PadPos padAndRow,
TPCFragmentTime localTime,
size_t positionOffset)
474#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
475 if (padAndRow.getRow() >= GPUTPCGeometry::NROWS) {
492 if (
charge < 1023.f) [[likely]] {
493 auto gain =
clusterer.GetConstantMem()->calibObjects.tpcPadGain->getGainCorrection(sector, padAndRow.getRow(), padAndRow.getPad());
500GPUd() uint16_t GPUTPCCFDecodeZSLinkBase::FillWithInvalid(processorType& clusterer, int32_t iThread, int32_t nThreads, uint32_t pageDigitOffset, uint16_t
nSamples)
515GPUd()
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)
517 Decode<GPUTPCCFDecodeZSDenseLink>(nBlocks, nThreads, iBlock, iThread, smem, clusterer, firstHBF, tpcTimeBinCut);
524 const auto* rawDataHeader = Peek<header::RAWDataHeader>(
ctx.page);
525 const auto* decHeader = Peek<TPCZSHDRV2>(
ctx.page, raw::RDHUtils::getMemorySize(*rawDataHeader) -
sizeof(
TPCZSHDRV2));
526 ConsumeHeader<header::RAWDataHeader>(
ctx.page);
528 uint16_t nSamplesWritten = 0;
529 const uint16_t nSamplesInPage = decHeader->nADCsamples;
531 const auto* payloadEnd = Peek(pageStart, raw::RDHUtils::getMemorySize(*rawDataHeader) -
sizeof(
TPCZSHDRV2) - ((decHeader->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent) ? TPCZSHDRV2::TRIGGER_WORD_SIZE : 0));
532 const auto* nextPage = Peek(pageStart, TPCZSHDR::TPC_ZS_PAGE_SIZE);
534 const bool extendsToNextPage = decHeader->flags & TPCZSHDRV2::ZSFlags::payloadExtendsToNextPage;
538 int err = GPUErrors::ERROR_NONE;
541 err = GPUErrors::ERROR_TPCZS_VERSION_MISMATCH;
544 if (decHeader->magicWord != zerosupp_link_based::CommonHeader::MagicWordLinkZSMetaHeader) {
545 err = GPUErrors::ERROR_TPCZS_INVALID_MAGIC_WORD;
548 for (uint16_t
i = 0;
i < decHeader->nTimebinHeaders && !err;
i++) {
550 ptrdiff_t sizeLeftInPage = payloadEnd -
ctx.page;
551 if (sizeLeftInPage <= 0) {
552 err = GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW;
556 int16_t nSamplesWrittenTB = 0;
557 uint16_t nSamplesLeftInPage = nSamplesInPage - nSamplesWritten;
559 if (
i == decHeader->nTimebinHeaders - 1 && extendsToNextPage) {
560 if (raw::RDHUtils::getMemorySize(*rawDataHeader) != TPCZSHDR::TPC_ZS_PAGE_SIZE) {
561 err = GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW;
565 if ((uint16_t)(raw::RDHUtils::getPageCounter(rawDataHeader) + 1) == raw::RDHUtils::getPageCounter(nextPage)) {
566 nSamplesWrittenTB = DecodeTB<true>(smem, ctx, rawDataHeader, decHeader->cruID, nSamplesLeftInPage, payloadEnd, nextPage);
568 err = GPUErrors::ERROR_TPCZS_INCOMPLETE_HBF;
572 nSamplesWrittenTB = DecodeTB<false>(smem, ctx, rawDataHeader, decHeader->cruID, nSamplesLeftInPage, payloadEnd, nextPage);
576 if (nSamplesWrittenTB < 0) {
577 err = -nSamplesWrittenTB;
581 nSamplesWritten += nSamplesWrittenTB;
582 ctx.pageDigitOffset += nSamplesWrittenTB;
585 if (nSamplesWritten != nSamplesInPage) {
586 if (nSamplesWritten < nSamplesInPage) {
587 ctx.pageDigitOffset += FillWithInvalid(
ctx.clusterer,
ctx.iThread,
ctx.nThreads,
ctx.pageDigitOffset, nSamplesInPage - nSamplesWritten);
589 err = !err ? GPUErrors::ERROR_TPCZS_INVALID_NADC : err;
592 if (
ctx.iThread == 0 && err) {
593 [[maybe_unused]]
bool dumpPage =
false;
595 if (err == GPUErrors::ERROR_TPCZS_VERSION_MISMATCH) {
597 }
else if (err == GPUErrors::ERROR_TPCZS_INVALID_MAGIC_WORD) {
598 ctx.clusterer.raiseError(err, decHeader->magicWord);
599 }
else if (err == GPUErrors::ERROR_TPCZS_INCOMPLETE_HBF) {
600 ctx.clusterer.raiseError(err,
ctx.clusterer.mISector * 1000 + decHeader->cruID, raw::RDHUtils::getPageCounter(rawDataHeader), raw::RDHUtils::getPageCounter(nextPage));
601 }
else if (err == GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW) {
602 ctx.clusterer.raiseError(err, extendsToNextPage);
604 }
else if (err == GPUErrors::ERROR_TPCZS_INVALID_NADC) {
605 ctx.clusterer.raiseError(err, nSamplesInPage, nSamplesWritten, extendsToNextPage);
608 ctx.clusterer.raiseError(GPUErrors::ERROR_TPCZS_UNKNOWN, err);
611#ifdef GPUCA_CHECK_TPCZS_CORRUPTION
615 const char fname[64] =
"dump00.bin";
616 FILE*
foo = fopen(fname,
"w+b");
617 fwrite(pageStart, 1, TPCZSHDR::TPC_ZS_PAGE_SIZE,
foo);
624 return ctx.pageDigitOffset;
627template <
bool PayloadExtendsToNextPage>
629 GPUSharedMemory& smem,
631 const header::RAWDataHeader* rawDataHeader,
633 uint16_t nSamplesLeftInPage,
634 const uint8_t* payloadEnd,
635 const uint8_t* nextPage)
637#define MAYBE_PAGE_OVERFLOW(pagePtr) \
638 if constexpr (PayloadExtendsToNextPage) { \
639 if (pagePtr >= payloadEnd && pagePtr < nextPage) { \
640 ptrdiff_t diff = pagePtr - payloadEnd; \
641 pagePtr = nextPage; \
642 ConsumeBytes(pagePtr, sizeof(header::RAWDataHeader) + diff); \
645 if (pagePtr > payloadEnd) { \
646 return -GPUErrors::ERROR_TPCZS_PAGE_OVERFLOW; \
650#define PEEK_OVERFLOW(pagePtr, offset) \
651 (*(PayloadExtendsToNextPage && (pagePtr) < nextPage && (pagePtr) + (offset) >= payloadEnd \
652 ? nextPage + sizeof(header::RAWDataHeader) + ((pagePtr) + (offset) - payloadEnd) \
653 : (pagePtr) + (offset)))
655#define TEST_BIT(x, bit) static_cast<bool>((x) & (1 << (bit)))
658 static_assert(NTHREADS == GPUCA_WARP_SIZE,
"Decoding TB Headers in parallel assumes block size is a single warp.");
663 uint16_t tbbHdr = ConsumeByte(
ctx.page);
665 tbbHdr |=
static_cast<uint16_t
>(ConsumeByte(
ctx.page)) << CHAR_BIT;
668 uint8_t nLinksInTimebin = tbbHdr & 0x000F;
669 uint16_t linkBC = (tbbHdr & 0xFFF0) >> 4;
670 int32_t timeBin = (linkBC + (uint64_t)(raw::RDHUtils::getHeartBeatOrbit(*rawDataHeader) -
ctx.firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN;
672 int16_t nSamplesInTB = 0;
675 for (uint8_t iLink = 0; iLink < nLinksInTimebin; iLink++) {
676 uint8_t timebinLinkHeaderStart = ConsumeByte(
ctx.page);
679 if (
ctx.iThread == 0) {
680 smem.linkIds[iLink] = timebinLinkHeaderStart & 0b00011111;
682 bool bitmaskIsFlat = timebinLinkHeaderStart & 0b00100000;
684 uint16_t bitmaskL2 = 0x03FF;
685 if (not bitmaskIsFlat) {
686 bitmaskL2 =
static_cast<uint16_t
>(timebinLinkHeaderStart & 0b11000000) << 2 |
static_cast<uint16_t
>(ConsumeByte(
ctx.page));
690 int32_t nBytesBitmask = CAMath::Popcount(bitmaskL2);
692 for (int32_t chan =
ctx.iThread; chan < CAMath::nextMultipleOf<NTHREADS>(80); chan += NTHREADS) {
693 int32_t chanL2Idx = chan / 8;
694 bool l2 =
TEST_BIT(bitmaskL2, chanL2Idx);
696 int32_t chanByteOffset = nBytesBitmask - 1 - CAMath::Popcount(bitmaskL2 >> (chanL2Idx + 1));
700 int32_t nSamplesStep;
701 int32_t threadSampleOffset = CfUtils::warpPredicateScan(myChannelHasData, &nSamplesStep);
703 if (myChannelHasData) {
704 smem.rawFECChannels[nSamplesInTB + threadSampleOffset] = chan;
707 nSamplesInTB += nSamplesStep;
710 ConsumeBytes(
ctx.page, nBytesBitmask);
713 if (
ctx.iThread == 0) {
714 smem.samplesPerLinkEnd[iLink] = nSamplesInTB;
721 if (nSamplesInTB > nSamplesLeftInPage) {
722 return -GPUErrors::ERROR_TPCZS_INVALID_NADC;
727 const uint8_t* adcData = ConsumeBytes(
ctx.page, (nSamplesInTB * DECODE_BITS + 7) / 8);
730 bool discardTimeBin = not frag.contains(timeBin);
731 discardTimeBin |= (
ctx.tpcTimeBinCut > 0 && timeBin >
ctx.tpcTimeBinCut);
733 if (discardTimeBin) {
734 return FillWithInvalid(
ctx.clusterer,
ctx.iThread, NTHREADS,
ctx.pageDigitOffset, nSamplesInTB);
739 for (uint16_t sample =
ctx.iThread; sample < nSamplesInTB; sample += NTHREADS) {
740 const uint16_t adcBitOffset = sample * DECODE_BITS;
741 uint16_t adcByteOffset = adcBitOffset / CHAR_BIT;
742 const uint8_t adcOffsetInByte = adcBitOffset - adcByteOffset * CHAR_BIT;
744 static_assert(DECODE_BITS <=
sizeof(uint16_t) * CHAR_BIT);
747 for (uint8_t
bits = 0;
bits < DECODE_BITS;
bits += CHAR_BIT) {
751 adc >>= adcOffsetInByte;
753 while (smem.samplesPerLinkEnd[iLink] <= sample) {
757 int32_t rawFECChannelLink = smem.rawFECChannels[sample];
760 o2::tpc::PadPos padAndRow = GetPadAndRowFromFEC(
ctx.clusterer, cru, rawFECChannelLink, smem.linkIds[iLink]);
762 float charge = ADCToFloat(
adc, DECODE_MASK, DECODE_BITS_FACTOR);
763 WriteCharge(
ctx.clusterer,
charge, padAndRow, frag.toLocal(timeBin),
ctx.pageDigitOffset + sample);
773#undef MAYBE_PAGE_OVERFLOW
778 constexpr uint8_t N_BITS_PER_ENTRY =
sizeof(*chan) * CHAR_BIT;
779 const uint8_t entryIndex = chanIndex / N_BITS_PER_ENTRY;
780 const uint8_t bitInEntry = chanIndex % N_BITS_PER_ENTRY;
781 return chan[entryIndex] & (1 << bitInEntry);
#define GPUCA_GET_THREAD_COUNT(...)
#define GPUCA_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
GPUd() const expr uint32_t MultivariatePolynomialHelper< Dim
const track::TrackFitContext< NLayers > const TrackFollowContext< NLayers > & ctx
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]
o2::tpc::PadPos FECIDToPadPos[TPC_FEC_IDS_IN_SECTOR]
unsigned char nTimeBinSpan
unsigned short timeOffset
coder decode(ctfImage, triggersD, clustersD)