mirror of https://github.com/openXC7/prjxray.git
108 lines
2.6 KiB
C++
108 lines
2.6 KiB
C++
#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;
|
|
}
|
|
}
|