Line Code
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