mirror of https://github.com/openXC7/prjxray.git
61 lines
1.2 KiB
C++
61 lines
1.2 KiB
C++
#include <prjxray/xilinx/xc7series/ecc.h>
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
|
|
namespace prjxray {
|
|
namespace xilinx {
|
|
namespace xc7series {
|
|
|
|
constexpr size_t kECCFrameNumber = 0x32;
|
|
|
|
uint32_t icap_ecc(uint32_t idx, uint32_t data, uint32_t ecc) {
|
|
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;
|
|
}
|
|
|
|
static uint32_t calculateECC(const std::vector<uint32_t>& data) {
|
|
uint32_t ecc = 0;
|
|
for (size_t ii = 0; ii < data.size(); ++ii) {
|
|
ecc = xc7series::icap_ecc(ii, data[ii], ecc);
|
|
}
|
|
return ecc;
|
|
}
|
|
|
|
void updateECC(std::vector<uint32_t>& data) {
|
|
assert(data.size() >= kECCFrameNumber);
|
|
// Replace the old ECC with the new.
|
|
data[kECCFrameNumber] &= 0xFFFFE000;
|
|
data[kECCFrameNumber] |= (calculateECC(data) & 0x1FFF);
|
|
}
|
|
|
|
} // namespace xc7series
|
|
} // namespace xilinx
|
|
} // namespace prjxray
|