Added ICAP CRC and ECC calculations and tests

Signed-off-by: Herbert Poetzl <herbert@13thfloor.at>
This commit is contained in:
Herbert Poetzl 2018-01-30 10:26:00 +01:00 committed by Rick Altherr
parent 414210db26
commit 86f49cc9da
5 changed files with 113 additions and 1 deletions

View File

@ -53,7 +53,9 @@ if (PRJXRAY_BUILD_TESTING)
xilinx/xc7series/configuration_packetizer_test.cc
xilinx/xc7series/global_clock_region_test.cc
xilinx/xc7series/part_test.cc
xilinx/xc7series/row_test.cc)
xilinx/xc7series/row_test.cc
xilinx/xc7series/crc_test.cc
xilinx/xc7series/ecc_test.cc)
target_link_libraries(xilinx_xc7series_test libprjxray gtest_main)
add_test(NAME xilinx_xc7series_test
COMMAND xilinx_xc7series_test

View File

@ -0,0 +1,32 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CRC_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CRC_H_
#include <cstdint>
namespace prjxray {
namespace xilinx {
namespace xc7series {
// Extend the current CRC value with one address (5bit) and data (32bit)
// pair and return the newly computed CRC value
uint32_t icap_crc(uint32_t addr, uint32_t data, uint32_t prev) {
uint64_t val = ((uint64_t)addr << 32) | data;
uint64_t crc = prev;
uint64_t poly = 0x82F63B78L << 1; // CRC-32C (Castagnoli)
for (int i = 0; i < 37; i++) {
if ((val & 1) != (crc & 1))
crc ^= poly;
val >>= 1;
crc >>= 1;
}
return crc;
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CRC_H_

View File

@ -0,0 +1,50 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_
#include <cstdint>
namespace prjxray {
namespace xilinx {
namespace xc7series {
// Extend the current ECC code with one data word (32 bit) at a given
// index in the configuration packet and return the new ECC code.
uint32_t icap_ecc(uint32_t idx, uint32_t data, uint32_t ecc) {
uint32_t off = idx * 32;
if (idx > 0x25) // avoid 0x800
off += 0x1360;
else if (idx > 0x6) // avoid 0x400
off += 0x1340;
else // avoid lower
off += 0x1320;
if (idx == 0x32) // mask ECC
data &= 0xFFFFE000;
for (int i = 0; i < 32; i++) {
if (data & 1)
ecc ^= off + 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;
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_

View File

@ -0,0 +1,13 @@
#include <prjxray/xilinx/xc7series/crc.h>
#include <gtest/gtest.h>
namespace xc7series = prjxray::xilinx::xc7series;
TEST(IcapCrcTest, SimpleTests) {
EXPECT_EQ(xc7series::icap_crc(0, 0, 0), (uint32_t)0x0);
EXPECT_EQ(xc7series::icap_crc(~0, ~0, 0), 0xBF86D4DF);
EXPECT_EQ(xc7series::icap_crc(0, 0, ~0), 0xC631E365);
EXPECT_EQ(xc7series::icap_crc(1 << 4, 0, 0), 0x82F63B78);
}

View File

@ -0,0 +1,15 @@
#include <prjxray/xilinx/xc7series/ecc.h>
#include <gtest/gtest.h>
namespace xc7series = prjxray::xilinx::xc7series;
TEST(IcapEccTest, SimpleTests) {
EXPECT_EQ(xc7series::icap_ecc(0, 0, 0), (uint32_t)0x0);
EXPECT_EQ(xc7series::icap_ecc(0, 1, 0), (uint32_t)0x1320);
EXPECT_EQ(xc7series::icap_ecc(0x7, 1, 0), (uint32_t)0x1420);
EXPECT_EQ(xc7series::icap_ecc(0x26, 1, 0), (uint32_t)0x1820);
EXPECT_EQ(xc7series::icap_ecc(0x32, ~0, 0), (uint32_t)0x000019AC);
EXPECT_EQ(xc7series::icap_ecc(0x64, 0, 1), (uint32_t)0x00001001);
}