From 86f49cc9da61004ddf37398d1b68205813dad08f Mon Sep 17 00:00:00 2001 From: Herbert Poetzl Date: Tue, 30 Jan 2018 10:26:00 +0100 Subject: [PATCH] Added ICAP CRC and ECC calculations and tests Signed-off-by: Herbert Poetzl --- lib/CMakeLists.txt | 4 +- lib/include/prjxray/xilinx/xc7series/crc.h | 32 ++++++++++++++ lib/include/prjxray/xilinx/xc7series/ecc.h | 50 ++++++++++++++++++++++ lib/xilinx/xc7series/crc_test.cc | 13 ++++++ lib/xilinx/xc7series/ecc_test.cc | 15 +++++++ 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 lib/include/prjxray/xilinx/xc7series/crc.h create mode 100644 lib/include/prjxray/xilinx/xc7series/ecc.h create mode 100644 lib/xilinx/xc7series/crc_test.cc create mode 100644 lib/xilinx/xc7series/ecc_test.cc diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4b751d68..81735b56 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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 diff --git a/lib/include/prjxray/xilinx/xc7series/crc.h b/lib/include/prjxray/xilinx/xc7series/crc.h new file mode 100644 index 00000000..81daacc4 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/crc.h @@ -0,0 +1,32 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CRC_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_CRC_H_ + +#include + +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_ diff --git a/lib/include/prjxray/xilinx/xc7series/ecc.h b/lib/include/prjxray/xilinx/xc7series/ecc.h new file mode 100644 index 00000000..a9ecf0d6 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/ecc.h @@ -0,0 +1,50 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_ + +#include + +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_ diff --git a/lib/xilinx/xc7series/crc_test.cc b/lib/xilinx/xc7series/crc_test.cc new file mode 100644 index 00000000..72e6ef3c --- /dev/null +++ b/lib/xilinx/xc7series/crc_test.cc @@ -0,0 +1,13 @@ +#include + +#include + +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); +} + diff --git a/lib/xilinx/xc7series/ecc_test.cc b/lib/xilinx/xc7series/ecc_test.cc new file mode 100644 index 00000000..de53a31b --- /dev/null +++ b/lib/xilinx/xc7series/ecc_test.cc @@ -0,0 +1,15 @@ +#include + +#include + +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); +} +