blob: 7fe865da9b74e76471abe572a455447e9e0d5aff [file] [log] [blame]
#include "ecc.h"
#include <cassert>
#include <iostream>
const std::unordered_map<std::string, size_t> 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<uint32_t>& 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<uint32_t>& 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;
}
}