ATLAS Offline Software
Loading...
Searching...
No Matches
NSWTriggerSTGL1AElink.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
5
8#include "ers/ers.h"
9#include <cmath>
10#include <cstddef>
11#include <iterator>
12#include <sstream>
13#include <stdexcept>
14#include <string>
15
16Muon::nsw::NSWTriggerSTGL1AElink::NSWTriggerSTGL1AElink(const uint32_t* bs, const uint32_t remaining)
17 : NSWTriggerElink(bs, remaining), m_data{bs, remaining} {
18 // TODO: once format finalized, checking a minimum size
19
20 // 2 felix header 32b words already decoded;
21 constexpr static auto START_DATA = std::size_t{2 * 32};
22 auto readPointer = std::size_t{START_DATA};
23
25 decode_header(readPointer, m_packet_version);
26 decode_data(readPointer, m_packet_version);
27 decode_trailer(readPointer);
28}
29
30void Muon::nsw::NSWTriggerSTGL1AElink::decode_header(std::size_t& readPointer, int& version) {
31
32 // This part is constant for all versions
41
42 ERS_DEBUG(2, Muon::nsw::format("\n TP header: \n"
43 " fradID: {}\n"
44 " sectID: {}\n"
45 " EC: {}\n"
46 " flags: {}\n"
47 " BCID: {}\n"
48 " orbit: {}\n"
49 " spare: {}\n"
50 " L1ID: {}",
52
53 if (version == 1)
54 {
65
67 }
68 else
69 {
71 if (m_l1a_versionID == 1)
72 {
73 version = 2;
74 }
75 else if (m_l1a_versionID == 3)
76 {
77 version = m_l1a_versionID;
78 }
79 else
80 {
81 Muon::nsw::NSWTriggerException e ( Muon::nsw::format( "Stgc packet version not existent (corrupted message) expected 3, got ({})", m_l1a_versionID));
82 throw e;
83
84 }
99 }
100
101}
102
104{
107
108 if (anchor == anchor_value)
109 {
110 return 1;
111 }
112
113 return -1;
114}
115
116void Muon::nsw::NSWTriggerSTGL1AElink::decode_data_v3(std::size_t& readPointer, int version) {
117
118 auto PADDING_BITS_END = std::size_t{16};
119
120
121 const auto endOfData = m_wordCountFlx * WORD_SIZE - Muon::nsw::STGTPL1A::size_trailer_CRC - PADDING_BITS_END;
122
123 while (readPointer < endOfData) {
124 static constexpr auto SIZE_DATA_HEADER = STGTPL1A::size_stream_head_nbits + STGTPL1A::size_stream_head_nwords +
126 if (readPointer + SIZE_DATA_HEADER > endOfData) {
127 throw std::length_error(
128 Muon::nsw::format("Read pointer ({}) would excede memory dedicated to data chunks ({}) while parsing the header (size: {})",
129 readPointer, endOfData, SIZE_DATA_HEADER));
130 }
131 const auto header_data = decode_data_header_v3(readPointer, version);
132 if (header_data.total_expected_size > m_wordCountFlx * WORD_SIZE - readPointer + 1) {
133 throw std::length_error(Muon::nsw::format("STG TP stream size {} larger than expected packet size {}",
134 header_data.total_expected_size,
135 m_wordCountFlx * WORD_SIZE - readPointer + 1));
136 }
137 if (header_data.nwords * header_data.data_size + readPointer > endOfData) {
138 throw std::length_error(Muon::nsw::format("Requested to decode {} bits but only {} bits are remaining",
139 header_data.nwords * header_data.data_size, endOfData - readPointer));
140 }
141 m_stream_data.push_back(decode_data_payload_v3(readPointer, header_data, version));
142 }
143 analyze_data_v3(version);
144}
145
146void Muon::nsw::NSWTriggerSTGL1AElink::decode_data(std::size_t& readPointer, int version) {
147 if (version == 3)
148 {
149 return decode_data_v3(readPointer, version);
150 }
151 auto PADDING_BITS_END = std::size_t{16};
152
153 const auto endOfData = m_wordCountFlx * WORD_SIZE - Muon::nsw::STGTPL1A::size_trailer_CRC - PADDING_BITS_END;
154 while (readPointer < endOfData) {
155 static constexpr auto SIZE_DATA_HEADER = STGTPL1A::size_stream_head_nbits + STGTPL1A::size_stream_head_nwords +
157 if (readPointer + SIZE_DATA_HEADER > endOfData) {
158 throw std::length_error(
159 Muon::nsw::format("Read pointer ({}) would excede memory dedicated to data chunks ({}) while parsing the header (size: {})",
160 readPointer, endOfData, SIZE_DATA_HEADER));
161 }
162 const auto header_data = decode_data_header(readPointer, version);
163
164 if (header_data.total_expected_size > m_wordCountFlx - ceil(readPointer / WORD_SIZE ) + 1) {
165 throw std::length_error(Muon::nsw::format("STG TP stream size {} larger than expected packet size {}",
166 header_data.total_expected_size,
167 m_wordCountFlx - ceil(readPointer / WORD_SIZE ) + 1));
168 }
169 if (header_data.nwords * header_data.data_size + readPointer > endOfData) {
170 throw std::length_error(Muon::nsw::format("Requested to decode {} bits but only {} bits are remaining",
171 header_data.nwords * header_data.data_size, endOfData - readPointer));
172 }
173
174 m_stream_data.push_back(decode_data_payload(readPointer, header_data, version));
175 }
176 analyze_data(version);
177}
178
180 std::size_t& readPointer, int version) {
181
182
183 if (version != 3){
184 throw std::invalid_argument("decode_data_header_v3 version should be exactly 3");
185 }
186
187 size_t felix_word_size = WORD_SIZE_DOUBLE;
188 auto PADDING_BITS_END = std::size_t{16};
191 const auto current_stream_head_fifo_size = decode(readPointer, STGTPL1A::size_stream_head_fifo_size);
192 const auto current_stream_head_streamID = decode(readPointer, STGTPL1A::size_stream_head_streamID);
193 const auto total_expected_size = stream_head_nbits * stream_head_nwords;
194 auto endOfData = m_wordCountFlx * felix_word_size - Muon::nsw::STGTPL1A::size_trailer_CRC - PADDING_BITS_END;
195 size_t current_stream_head_nbits = 0;
196 size_t current_stream_head_nwords = 0;
197
198 switch (current_stream_head_streamID)
199 {
201 current_stream_head_nbits = STGTPPad::size_v3;
202 break;
204 current_stream_head_nbits = STGTPSegments::size_v3;
205 break;
207 current_stream_head_nbits = STGTPMMData::size_v3;
208 break;
209 default:
210 break;
211 }
212
213 if (current_stream_head_nbits == 0 )
214 {
215 throw std::runtime_error( "Corrupted message - sTGC stream has an unrecognized stream header");
216 }
217
218 if (readPointer + total_expected_size > endOfData)
219 {
220 throw std::runtime_error("Corrupted message - sTGC expected size goes beyond the end of data");
221 }
222
223 current_stream_head_nwords = (stream_head_nwords == 0) ? 0 : total_expected_size / current_stream_head_nbits;
224 size_t data_size = std::ceil(total_expected_size / felix_word_size);
225
226 // in version 3 nbits correspond to either 16 or 32 bits. There is a stable packet size that we use and
227 // we extract it from the code. The 16 or 32 bits is a consequence of an optimization in the firmware that
228 // results in big gains wrt routing and resources
229 m_stream_head_nbits.push_back(current_stream_head_nbits);
230 m_stream_head_nwords.push_back(current_stream_head_nwords);
231 m_stream_head_fifo_size.push_back(current_stream_head_fifo_size);
232 m_stream_head_streamID.push_back(current_stream_head_streamID);
233
234
235
236 ERS_DEBUG(2, Muon::nsw::format("stream_head_nbits: {}", current_stream_head_nbits));
237 ERS_DEBUG(2, Muon::nsw::format("stream_head_nwords: {}", current_stream_head_nwords));
238 ERS_DEBUG(2, Muon::nsw::format("stream_head_fifo_size: {}", current_stream_head_fifo_size));
239 ERS_DEBUG(2, Muon::nsw::format("stream_head_streamID: {}", current_stream_head_streamID));
240 ERS_DEBUG(2, Muon::nsw::format("total_expected_size: {}", total_expected_size));
241 ERS_DEBUG(2, Muon::nsw::format("m_wordCountFlx: {}, ceil(readPointer/{}): {}", m_wordCountFlx,felix_word_size,
242 ceil(readPointer / felix_word_size)));
243
244
245 return {current_stream_head_nbits, current_stream_head_nwords, current_stream_head_fifo_size,
246 current_stream_head_streamID, total_expected_size, data_size};
247}
248
250 std::size_t& readPointer, int version) {
251 if (version >= 3){
252 return decode_data_header_v3(readPointer, version);
253 }
254 const auto current_stream_head_nbits = decode(readPointer, STGTPL1A::size_stream_head_nbits);
255 const auto current_stream_head_nwords = decode(readPointer, STGTPL1A::size_stream_head_nwords);
256 const auto current_stream_head_fifo_size = decode(readPointer, STGTPL1A::size_stream_head_fifo_size);
257 const auto current_stream_head_streamID = decode(readPointer, STGTPL1A::size_stream_head_streamID);
258
259 // zero padding to multiples of 16bits - TP logic - this is the real number
260 // of bits to read
261 const auto corrected_current_stream_head_nbits = correct_size_for_padding(current_stream_head_nbits);
262
263 m_stream_head_nbits.push_back(corrected_current_stream_head_nbits);
264 m_stream_head_nwords.push_back(current_stream_head_nwords);
265 m_stream_head_fifo_size.push_back(current_stream_head_fifo_size);
266 m_stream_head_streamID.push_back(current_stream_head_streamID);
267
268 size_t word_size = WORD_SIZE_DOUBLE;
269 const auto data_size = static_cast<std::size_t>(std::ceil(corrected_current_stream_head_nbits / word_size));
270 const auto total_expected_size = data_size * current_stream_head_nwords;
271
272 ERS_DEBUG(2, Muon::nsw::format("stream_head_nbits: {}", corrected_current_stream_head_nbits));
273 ERS_DEBUG(2, Muon::nsw::format("stream_head_nwords: {}", current_stream_head_nwords));
274 ERS_DEBUG(2, Muon::nsw::format("stream_head_fifo_size: {}", current_stream_head_fifo_size));
275 ERS_DEBUG(2, Muon::nsw::format("stream_head_streamID: {}", current_stream_head_streamID));
276 ERS_DEBUG(2, Muon::nsw::format("total_expected_size: {}", data_size * current_stream_head_nwords));
277 ERS_DEBUG(2, Muon::nsw::format("m_wordCountFlx: {}, ceil(readPointer/{}): {}", m_wordCountFlx, word_size,
278 ceil(readPointer / word_size)));
279
280 return {corrected_current_stream_head_nbits, current_stream_head_nwords, current_stream_head_fifo_size,
281 current_stream_head_streamID, total_expected_size, data_size};
282}
283
284std::vector<std::vector<std::uint32_t>> Muon::nsw::NSWTriggerSTGL1AElink::decode_data_payload_v3(
285 std::size_t& readPointer, const DataHeader& header, int version) const {
286 std::vector<std::vector<std::uint32_t>> current_stream_data{};
287
288 if (version < 3){
289 throw std::invalid_argument("decode_data_header_v3 version should be at least 3");
290 }
291
292 size_t word_size = WORD_SIZE;
293 size_t felix_n_words = (header.nwords == 0 ) ? 0 : std::ceil(header.data_size / header.nwords); // the number of felix words per stream word
294 for (std::size_t i = 0; i < header.nwords; ++i) {
295 std::vector<std::uint32_t> data{};
296 for (std::size_t j = 0; j < felix_n_words; ++j) {
297 data.push_back(decode(readPointer, word_size));
298 }
299 current_stream_data.push_back(std::move(data));
300 }
301 return current_stream_data;
302}
303std::vector<std::vector<std::uint32_t>> Muon::nsw::NSWTriggerSTGL1AElink::decode_data_payload(
304 std::size_t& readPointer, const DataHeader& header, int version) const {
305 std::vector<std::vector<std::uint32_t>> current_stream_data{};
306
307 if (version >= 3)
308 return decode_data_payload_v3( readPointer, header, version);
309 size_t word_size = WORD_SIZE;
310 for (std::size_t i = 0; i < header.nwords; ++i) {
311 std::vector<std::uint32_t> data{};
312 for (std::size_t j = 0; j < header.data_size; ++j) {
313 data.push_back(decode(readPointer, word_size));
314 }
315 current_stream_data.push_back(std::move(data));
316 }
317 return current_stream_data;
318
319}
320
322 // TODO: warning: how the swROD is behaving if the last work is a uint16 only? Just 0-padding?
324}
325
326std::uint64_t Muon::nsw::NSWTriggerSTGL1AElink::decode(std::size_t& readPointer, const std::size_t size) const {
328}
329
331
332 size_t word_size = WORD_SIZE_DOUBLE;
333 auto counterChunk = std::size_t{0};
334 for (const auto& dataChunk : m_stream_data) {
335 for (const auto& dataWord : dataChunk) {
336 const auto expectedSize =
337 static_cast<std::size_t>(std::ceil(m_stream_head_nbits.at(counterChunk) / word_size));
338 if (std::size(dataWord) != expectedSize) {
339 throw std::length_error(Muon::nsw::format("Stream data size {} does not match expected number of messages {}",
340 std::size(dataWord), expectedSize));
341 }
342 switch (m_stream_head_streamID.at(counterChunk)) {
344 m_pad_packets.emplace_back(dataWord,version);
345 break;
347 m_segment_packets.emplace_back(dataWord,version);
348 break;
350 m_mm_packets.emplace_back(dataWord,version);
351 break;
353 m_strip_packets.emplace_back(dataWord,version);
354 break;
355 default:
356 throw std::runtime_error(Muon::nsw::format("Invalid stream type {}", m_stream_head_streamID.at(counterChunk)));
357 }
358 }
359 ++counterChunk;
360 }
361
362}
363
365 if (version >= 3){
366 return analyze_data_v3(version);
367 }
368
369 size_t word_size = WORD_SIZE_DOUBLE;
370 auto counterChunk = std::size_t{0};
371 for (const auto& dataChunk : m_stream_data) {
372 for (const auto& dataWord : dataChunk) {
373 const auto expectedSize =
374 static_cast<std::size_t>(std::ceil(m_stream_head_nbits.at(counterChunk) / word_size));
375 if (std::size(dataWord) != expectedSize) {
376 throw std::length_error(Muon::nsw::format("Stream data size {} does not match expected number of messages {}",
377 std::size(dataWord), expectedSize));
378 }
379 switch (m_stream_head_streamID.at(counterChunk)) {
381 m_pad_packets.emplace_back(dataWord,version);
382 break;
384 m_segment_packets.emplace_back(dataWord,version);
385 break;
387 m_strip_packets.emplace_back(dataWord,version);
388 break;
389 default:
390 throw std::runtime_error(Muon::nsw::format("Invalid stream type {}", m_stream_head_streamID.at(counterChunk)));
391 }
392 }
393 ++counterChunk;
394 }
395}
396
397std::uint64_t Muon::nsw::NSWTriggerSTGL1AElink::correct_size_for_padding(const std::uint64_t initial) {
398 static constexpr auto PADDING = 16;
399 if (initial % PADDING) {
400 return ((initial + PADDING - 1) / PADDING) * PADDING;
401 } else {
402 return initial;
403 }
404}
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
constexpr uint32_t version1_anchor_value
constexpr int size_l1a_open_BCID_offset
constexpr int size_stream_head_fifo_size
constexpr int size_stream_head_streamID
constexpr int size_l1a_link_const
constexpr int size_l1a_local_req_BCID
constexpr int size_l1a_close_BCID_offset
constexpr int size_l1a_local_rel_BCID
constexpr int size_l1a_timeout_config
constexpr int size_l1a_engine_snapshot
constexpr int size_l1a_req_BCID_offset
constexpr int size_l1a_close_BCID
constexpr int size_l1a_wdw_matching_engines_usage
constexpr int size_stream_head_nwords
constexpr int size_stream_head_nbits
constexpr int loc_version1_anchor
constexpr std::size_t size_v3
constexpr std::size_t pad_stream_header
constexpr std::size_t size_v3
constexpr std::size_t size_v3
std::string format(const std::string &str, const T &arg)
constexpr Target decode_at_loc(const std::span< const Source > words, std::size_t &start, const int offset, const std::size_t size)
Decode bits from data of words at read pointer + offset and NOT advance the read pointer.
constexpr Target decode_and_advance(const std::span< const Source > words, std::size_t &start, const std::size_t size)
Decode bits from data of words and advance the read pointer.