| /* | 
 |  * Copyright (C) 2017-2020  The Project X-Ray Authors. | 
 |  * | 
 |  * Use of this source code is governed by a ISC-style | 
 |  * license that can be found in the LICENSE file or at | 
 |  * https://opensource.org/licenses/ISC | 
 |  * | 
 |  * SPDX-License-Identifier: ISC | 
 |  */ | 
 | #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 |