1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
#include <iomanip>
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "EventFilter/L1TRawToDigi/interface/Block.h"
#define EDM_ML_DEBUG 1
namespace l1t {
const std::vector<unsigned int> MTF7Payload::block_patterns_ = {
// from l1t::mtf7::mtf7_block_t enum definition
mtf7::EvHd, // Event Record Header
mtf7::CnBlk, // Block of Counters
mtf7::ME, // ME Data Record
mtf7::RPC, // RPC Data Record
mtf7::GEM, // GEM Data Record
mtf7::ME0, // ME0 Data Record
mtf7::SPOut, // SP Output Data Record
mtf7::EvTr // Event Record Trailer
};
uint32_t BlockHeader::raw() const {
if (type_ == MP7) {
LogTrace("L1T") << "Writing MP7 link header";
return ((id_ & ID_mask) << ID_shift) | ((size_ & size_mask) << size_shift) |
((capID_ & capID_mask) << capID_shift) | ((flags_ & flags_mask) << flags_shift);
} else if (type_ == CTP7) {
LogTrace("L1T") << "Writing CTP7 link header";
return flags_;
}
// if (type_ == MTF7) {
// LogTrace("L1T") << "Writing MTF7 link header";
// return ((id_ & ID_mask) << ID_shift) | ((size_ & size_mask) << size_shift) | ((capID_ & capID_mask) << capID_shift);
// }
LogTrace("L1T") << "Writing meaningless link header";
return 0;
}
BxBlocks Block::getBxBlocks(unsigned int payloadWordsPerBx, bool bxHeader) const {
BxBlocks bxBlocks;
// For MP7 format
unsigned int wordsPerBx = payloadWordsPerBx;
if (bxHeader) {
++wordsPerBx;
}
// Calculate how many BxBlock objects can be made with the available payload
unsigned int nBxBlocks = payload_.size() / wordsPerBx;
for (size_t bxCtr = 0; bxCtr < nBxBlocks; ++bxCtr) {
size_t startIdx = bxCtr * wordsPerBx;
auto startBxBlock = payload_.cbegin() + startIdx;
// Pick the words from the block payload that correspond to the BX and add a BxBlock to the BxBlocks
if (bxHeader) {
bxBlocks.emplace_back(startBxBlock, startBxBlock + wordsPerBx);
} else {
bxBlocks.emplace_back(bxCtr, nBxBlocks, startBxBlock, startBxBlock + wordsPerBx);
}
}
return bxBlocks;
}
std::optional<Block> Payload::getBlock() {
if (end_ - data_ < getHeaderSize()) {
LogDebug("L1T") << "Reached end of payload";
return {};
}
if (data_[0] == 0xffffffff) {
LogDebug("L1T") << "Skipping padding word";
++data_;
return getBlock();
}
auto header = getHeader();
if (end_ - data_ < header.getSize()) {
edm::LogError("L1T") << "Expecting a block size of " << header.getSize() << " but only " << (end_ - data_)
<< " words remaining";
return {};
}
LogTrace("L1T") << "Creating block with size " << header.getSize();
Block res(header, data_, data_ + header.getSize());
data_ += header.getSize();
return res;
}
MP7Payload::MP7Payload(const uint32_t* data, const uint32_t* end, bool legacy_mc) : Payload(data, end) {
// For legacy MC (74 first MC campaigns) skip one empty word that was
// reserved for the header. With data, read out infrastructure
// version and algorithm version.
if (legacy_mc) {
LogTrace("L1T") << "Skipping " << std::hex << *data_;
++data_;
} else {
infra_ = data_[0];
algo_ = data_[1];
data_ += 2;
}
}
BlockHeader MP7Payload::getHeader() {
LogTrace("L1T") << "Getting header from " << std::hex << std::setw(8) << *data_;
return BlockHeader(data_++);
}
MTF7Payload::MTF7Payload(const uint32_t* data, const uint32_t* end) : Payload(data, end) {
const uint16_t* data16 = reinterpret_cast<const uint16_t*>(data);
const uint16_t* end16 = reinterpret_cast<const uint16_t*>(end);
if (end16 - data16 < header_size + counter_size + trailer_size) {
edm::LogError("L1T") << "MTF7 payload smaller than allowed!";
data_ = end_;
} else if ( // Check bits for EMTF Event Record Header
((data16[0] >> 12) != 0x9) || ((data16[1] >> 12) != 0x9) || ((data16[2] >> 12) != 0x9) ||
((data16[3] >> 12) != 0x9) || ((data16[4] >> 12) != 0xA) || ((data16[5] >> 12) != 0xA) ||
((data16[6] >> 12) != 0xA) || ((data16[7] >> 12) != 0xA) || ((data16[8] >> 15) != 0x1) ||
((data16[9] >> 15) != 0x0) || ((data16[10] >> 15) != 0x0) || ((data16[11] >> 15) != 0x0)) {
edm::LogError("L1T") << "MTF7 payload has invalid header!";
data_ = end_;
} else if ( // Check bits for EMTF MPC Link Errors
((data16[12] >> 15) != 0) || ((data16[13] >> 15) != 1) || ((data16[14] >> 15) != 0) ||
((data16[15] >> 15) != 0)) {
edm::LogError("L1T") << "MTF7 payload has invalid counter block!";
data_ = end_;
}
// Check bits for EMTF Event Record Trailer, get firmware version
algo_ = 0; // Firmware version
// Start after always present Counters block
for (unsigned i = DAQ_PAYLOAD_OFFSET; i < PAYLOAD_MAX_SIZE; i++) {
if (((data16[4 * i + 0] >> 12) == 0xF) && ((data16[4 * i + 1] >> 12) == 0xF) &&
((data16[4 * i + 2] >> 12) == 0xF) && ((data16[4 * i + 3] >> 12) == 0xF) &&
((data16[4 * i + 4] >> 12) == 0xE) && ((data16[4 * i + 5] >> 12) == 0xE) &&
((data16[4 * i + 6] >> 12) == 0xE) &&
((data16[4 * i + 7] >> 12) == 0xE)) { // Indicators for the Trailer block
algo_ = (((data16[4 * i + 2] >> 4) & 0x3F) << 9); // Year (6 bits)
algo_ |= (((data16[4 * i + 2] >> 0) & 0x0F) << 5); // Month (4 bits)
algo_ |= (((data16[4 * i + 4] >> 0) & 0x1F) << 0); // Day (5 bits)
break;
}
}
if (algo_ == 0) {
edm::LogError("L1T") << "MTF7 payload has no valid EMTF firmware version!";
data_ = end_;
}
}
int MTF7Payload::count(unsigned int pattern, unsigned int length) const {
unsigned int mask = 0;
for (; length > 0; length--)
mask = (mask << 4) | 0xf;
int count = 0;
for (const auto& p : block_patterns_)
count += (p & mask) == pattern;
return count;
}
bool MTF7Payload::valid(unsigned int pattern) const {
for (const auto& p : block_patterns_) {
if (p == pattern)
return true;
}
return false;
}
std::optional<Block> MTF7Payload::getBlock() {
if (end_ - data_ < 2)
return {};
const uint16_t* data16 = reinterpret_cast<const uint16_t*>(data_);
const uint16_t* end16 = reinterpret_cast<const uint16_t*>(end_);
// Read in blocks equivalent to 64 bit words, trying to match the
// pattern of first bits to what is deemed valid.
std::vector<uint32_t> payload;
unsigned int pattern = 0;
unsigned int i = 0;
for (; i < max_block_length_ and data16 + (i + 1) * 4 <= end16; ++i) {
for (int j = 0; j < 4; ++j) {
auto n = i * 4 + j;
pattern |= (data16[n] >> 15) << n;
payload.push_back(data16[n]);
}
if (count(pattern, i + 1) == 1 and valid(pattern))
break;
}
if (not valid(pattern)) {
edm::LogWarning("L1T") << "MTF7 block with unrecognized id 0x" << std::hex << pattern;
return {};
}
data_ += (i + 1) * 2;
return Block(pattern, payload, 0, MTF7);
}
CTP7Payload::CTP7Payload(const uint32_t* data, const uint32_t* end, amc::Header amcHeader)
: Payload(data, end), amcHeader_(amcHeader) {
if (not(*data_ == 0xA110CA7E)) {
edm::LogError("L1T") << "CTP7 block with invalid header:" << std::hex << *data_;
}
++data_;
bx_per_l1a_ = (*data_ >> 16) & 0xff;
calo_bxid_ = *data_ & 0xfff;
capId_ = 0;
six_hcal_feature_bits_ = (*data_ >> 15) & 0x1;
slot7_card_ = (*data_ >> 14) & 0x1;
if (bx_per_l1a_ > 1) {
edm::LogInfo("L1T") << "CTP7 block with multiple bunch crossings:" << bx_per_l1a_;
}
algo_ = amcHeader_.getUserData();
infra_ = 0;
++data_;
}
BlockHeader CTP7Payload::getHeader() {
// only one block type, use dummy id
unsigned blockId = 0;
// CTP7 header contains number of BX in payload and the bunch crossing ID
// Not sure how to map to generic BlockHeader variables, so just packing
// it all in flags variable
unsigned blockFlags = ((bx_per_l1a_ & 0xf) << 16) | (calo_bxid_ & 0xfff) | ((six_hcal_feature_bits_ & 0x1) << 15) |
((slot7_card_ & 0x1) << 14);
unsigned blockSize = (slot7_card_ == 1) ? 6 : ((192 + (int)six_hcal_feature_bits_ * 28) * (int)bx_per_l1a_);
return BlockHeader(blockId, blockSize, capId_, blockFlags, CTP7);
}
std::optional<Block> CTP7Payload::getBlock() {
if (end_ - data_ < getHeaderSize()) {
LogDebug("L1T") << "Reached end of payload";
return {};
}
if (capId_ > bx_per_l1a_) {
edm::LogWarning("L1T") << "CTP7 with more bunch crossings than expected";
}
auto header = getHeader();
if (end_ - data_ < header.getSize()) {
edm::LogError("L1T") << "Expecting a block size of " << header.getSize() << " but only " << (end_ - data_)
<< " words remaining";
return {};
}
LogTrace("L1T") << "Creating block with size " << header.getSize();
Block res(header, data_, data_ + header.getSize());
data_ += header.getSize();
capId_++;
return res;
}
} // namespace l1t
|