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
|
#include <iomanip>
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/Utilities/interface/calculateCRC32.h"
#include "EventFilter/L1TRawToDigi/interface/AMCSpec.h"
//#define EDM_ML_DEBUG 1
namespace amc {
BlockHeader::BlockHeader(unsigned int amc_no, unsigned int board_id, unsigned int size, unsigned int block) {
// Determine size
unsigned int max_block_no = 0;
if (size >= 0x13ff)
max_block_no = (size - 1023) / 4096;
if (block != max_block_no)
size = split_block_size;
else if (block != 0)
size -= split_block_size * max_block_no;
data_ = (static_cast<uint64_t>(size & Size_mask) << Size_shift) |
(static_cast<uint64_t>(block & BlkNo_mask) << BlkNo_shift) |
(static_cast<uint64_t>(amc_no & AmcNo_mask) << AmcNo_shift) |
(static_cast<uint64_t>(board_id & BoardID_mask) << BoardID_shift) | (1llu << Enabled_bit_shift) |
(1llu << Present_bit_shift);
if (block == getBlocks() - 1) {
// Last block
data_ |= (1llu << CRC_bit_shift) | (1llu << Valid_bit_shift) | (1llu << Length_bit_shift);
}
if (block == 0 && getBlocks() == 1) {
// Bits already zeroed - only one block
} else if (block == 0) {
// First of many blocks
data_ |= 1llu << More_bit_shift;
} else if (block == getBlocks() - 1) {
// Last of many blocks
data_ |= 1llu << Segmented_bit_shift;
} else {
// Intermediate of many blocks
data_ |= (1llu << More_bit_shift) | (1llu << Segmented_bit_shift);
}
}
unsigned int BlockHeader::getBlocks() const {
// The first block of a segmented event has a size of 1023, all
// following have a max size of 4096. Segmentation only happens
// for AMC payloads >= 0x13ff 64 bit words.
unsigned int size = getSize();
if (size >= 0x13ff)
return (size - 1023) / 4096 + 1;
return 1;
}
unsigned int BlockHeader::getBlockSize() const {
// More and not Segmented means the first of multiple blocks. For
// these, getSize() returns the total size of the AMC packet, not the
// size of the first block.
if (getMore() && !getSegmented())
return split_block_size;
return getSize();
}
Header::Header(unsigned int amc_no,
unsigned int lv1_id,
unsigned int bx_id,
unsigned int size,
unsigned int or_n,
unsigned int board_id,
unsigned int user)
: data0_((uint64_t(amc_no & AmcNo_mask) << AmcNo_shift) | (uint64_t(lv1_id & LV1ID_mask) << LV1ID_shift) |
(uint64_t(bx_id & BX_mask) << BX_shift) | (uint64_t(size & Size_mask) << Size_shift)),
data1_((uint64_t(or_n & OrN_mask) << OrN_shift) | (uint64_t(board_id & BoardID_mask) << BoardID_shift) |
(uint64_t(user & User_mask) << User_shift)) {}
Trailer::Trailer(unsigned int crc, unsigned int lv1_id, unsigned int size)
: data_((uint64_t(crc & CRC_mask) << CRC_shift) | (uint64_t(lv1_id & LV1ID_mask) << LV1ID_shift) |
(uint64_t(size & Size_mask) << Size_shift)) {}
bool Trailer::check(unsigned int crc, unsigned int lv1_id, unsigned int size, bool mtf7_mode) const {
if ((crc != getCRC() || size != getSize() || (lv1_id & LV1ID_mask) != getLV1ID()) && !mtf7_mode) {
edm::LogWarning("L1T") << "Found AMC trailer with:"
<< "\n\tLV1 ID " << getLV1ID() << ", size " << getSize() << ", CRC " << std::hex
<< std::setw(8) << std::setfill('0') << getCRC() << std::dec << "\nBut expected:"
<< "\n\tLV1 ID " << (lv1_id & LV1ID_mask) << ", size " << size << ", CRC " << std::hex
<< std::setw(8) << std::setfill('0') << crc;
return false;
}
return true;
}
void Trailer::writeCRC(const uint64_t *start, uint64_t *end) {
std::string_view dstring(reinterpret_cast<const char *>(start), reinterpret_cast<const char *>(end) + 4);
auto crc = cms::calculateCRC32(dstring);
*end = ((*end) & ~(uint64_t(CRC_mask) << CRC_shift)) | (static_cast<uint64_t>(crc & CRC_mask) << CRC_shift);
}
Packet::Packet(unsigned int amc,
unsigned int board,
unsigned int lv1id,
unsigned int orbit,
unsigned int bx,
const std::vector<uint64_t> &load,
unsigned int user)
: block_header_(amc, board, load.size() + 3), // add 3 words for header (2) and trailer (1)
header_(amc, lv1id, bx, load.size() + 3, orbit, board, user),
trailer_(0, lv1id, load.size() + 3) {
auto hdata = header_.raw();
payload_.reserve(load.size() + 3);
payload_.insert(payload_.end(), hdata.begin(), hdata.end());
payload_.insert(payload_.end(), load.begin(), load.end());
payload_.insert(payload_.end(), trailer_.raw());
auto ptr = payload_.data();
Trailer::writeCRC(ptr, ptr + payload_.size() - 1);
}
void Packet::addPayload(const uint64_t *data, unsigned int size) {
payload_.insert(payload_.end(), data, data + size);
}
void Packet::finalize(unsigned int lv1, unsigned int bx, bool legacy_mc, bool mtf7_mode) {
if (legacy_mc) {
header_ =
Header(block_header_.getAMCNumber(), lv1, bx, block_header_.getSize(), 0, block_header_.getBoardID(), 0);
payload_.insert(payload_.begin(), {0, 0});
payload_.insert(payload_.end(), {0});
} else {
header_ = Header(payload_.data());
trailer_ = Trailer(&payload_.back());
std::string_view check(reinterpret_cast<const char *>(payload_.data()), payload_.size() * 8 - 4);
auto crc = cms::calculateCRC32(check);
trailer_.check(crc, lv1, header_.getSize(), mtf7_mode);
}
}
std::span<const uint64_t> Packet::block(unsigned int id) const {
if (id == 0 and id == block_header_.getBlocks() - 1) {
return std::span<const uint64_t>(payload_);
} else if (id == block_header_.getBlocks() - 1) {
return std::span<const uint64_t>(payload_.begin() + id * split_block_size, payload_.end());
} else {
return std::span<const uint64_t>(payload_.begin() + id * split_block_size,
payload_.begin() + (id + 1) * split_block_size);
}
}
} // namespace amc
|