#include "ecc.h" #include #include const std::unordered_map ECC::ecc_word_per_architecture = { {"Series7", 50}, {"UltraScale", 60}, {"UltraScalePlus", 45}}; uint32_t ECC::GetSeries7WordEcc(uint32_t idx, uint32_t data, uint32_t ecc) const { uint32_t val = idx * 32; // bit offset if (idx > 0x25) // avoid 0x800 val += 0x1360; else if (idx > 0x6) // avoid 0x400 val += 0x1340; else // avoid lower val += 0x1320; if (idx == 0x32) // mask ECC data &= 0xFFFFE000; for (int i = 0; i < 32; i++) { if (data & 1) ecc ^= val + i; data >>= 1; } if (idx == 0x64) { // last index uint32_t v = ecc & 0xFFF; v ^= v >> 8; v ^= v >> 4; v ^= v >> 2; v ^= v >> 1; ecc ^= (v & 1) << 12; // parity } return ecc; } uint64_t ECC::GetUSEccFrameOffset(int word, int bit) const { int nib = bit / 4; int nibbit = bit % 4; // ECC offset is expanded to 1 bit per nibble, // and then shifted based on the bit index in nibble // e.g. word 3, bit 9 // offset: 0b10100110010 - concatenate (3 + (255 - last_frame_index(e.g. // 92 for US+)) [frame offset] and 9/4 [nibble offset] becomes: // 0x10100110010 shifted by bit in nibble (9%4): 0x20200220020 uint32_t offset = (word + (255 - (frame_words_ - 1))) << 3 | nib; uint64_t exp_offset = 0; // Odd parity offset ^= (1 << 11); for (int i = 0; i < 11; i++) if (offset & (1 << i)) offset ^= (1 << 11); // Expansion for (int i = 0; i < 12; i++) if (offset & (1 << i)) exp_offset |= (1ULL << (4 * i)); return exp_offset << nibbit; }; uint64_t ECC::GetUSWordEcc(uint32_t idx, uint32_t data, uint64_t ecc) const { if (idx == ecc_word_) { data = 0x0; } if (idx == ecc_word_ + 1) { data &= 0xffff0000; } for (int i = 0; i < 32; i++) { if (data & 1) { ecc ^= GetUSEccFrameOffset(idx, i); } data >>= 1; } return ecc; } uint64_t ECC::CalculateECC(const std::vector& data) const { uint64_t ecc = 0; for (size_t w = 0; w < data.size(); ++w) { const uint32_t& word = data.at(w); if (architecture_ == "Series7") { ecc = GetSeries7WordEcc(w, word, ecc); } else { ecc = GetUSWordEcc(w, word, ecc); } } return ecc; } void ECC::UpdateFrameECC(std::vector& data) const { assert(data.size() >= ecc_word_); uint64_t ecc(CalculateECC(data)); if (architecture_ == "Series7") { data[ecc_word_] &= 0xffffe000; data[ecc_word_] |= ecc & 0x1fff; } else { data[ecc_word_] = ecc; data[ecc_word_ + 1] &= 0xffff0000; data[ecc_word_ + 1] |= (ecc >> 32) & 0xffff; } }