Problems with Spartan6 CRC calculation

N

Neil Steiner

Guest
I am unsuccessfully trying to update Spartan6 CRC checksums after I make
packet modifications. This is not a problem for Virtex/E/2/2P/4/5/6/7
or for Spartan3E, but Spartan6 is a different story altogether. I
posted this same question on Xilinx Forums, but there have been no
responses.

I know that Spartan6 packets consist of 16-bit words, unlike the 32-bit
words of the other architectures listed above. UG380 also states that
"The Cyclic Redundancy Check register utilizes a standard 32-bit CRC
checksum algorithm." My perhaps incorrect assumption is that the
polynomial is the same CRC-32C (Castagnoli) polynomial as for
Virtex4/5/6/7 families. I am also assuming that only "payload words"
(after the packet header) factor into the calculation, just as with the
other architectures, and UG380 explicitly shows the address length as 6
bits.

Does anybody know how to calculate this correctly for Spartan6? If
anyone cares to see the logic I'm trying to use, it's quite similar to
what works correctly for all the other Xilinx architectures:

// begin CRC calculation
uint32_t address = 0;
iterator p = begin();
iterator e = end();
// CRC-32C (Castagnoli) polynomial for Virtex4/5/6/7 families
boost::crc_basic<32> crc32(0x1edc6f41, 0, 0, false, true);
while(p < e) {
// look up the current packet
const Spartan6Packet& packet = *p++;
// only process write packets with non-zero payload length
if(!packet.isWrite()) continue;
address = packet.getAddress();
uint32_t wordCount = packet.getWordCount();
if(wordCount == 0) continue;
// CRC register write (this is what compares the expected and
supplied CRC values)
if(address == crcRegister) {
printf("Expected CRC32: %8.8x\n", (uint32_t(packet[1]) <<
16) | packet[2]);
printf("Calculated CRC32: %8.8x\n", crc32.checksum());
*(p-1) = Spartan6Packet::makeType1Write(crcRegister,
crc32.checksum());
crc32.reset();
// reset CRC command
} else if(address == cmdRegister && wordCount >= 1 && packet[1]
== rcrcCommand) {
crc32.reset();
// process packet contents
} else {
uint32_t j;
uint32_t mask;
for(uint32_t i = 1; i <= wordCount; i++) {
uint32_t word = packet;
//printf("Address: %4.4x\n", address);
//printf("Word: %8.8x\n", word);
for(j = 0, mask = 1; j < 16; j++, mask <<= 1) {
crc32.process_bit((word & mask) ? 1 : 0);
}
for(j = 0, mask = 1; j < addressLength; j++, mask <<= 1) {
crc32.process_bit((address & mask) ? 1 : 0);
}
}
// process the Auto CRC
if(autoCrc && address == fdriRegister) {
printf("Expected Auto CRC32: %8.8x\n",
(uint32_t((*p)[0]) << 16) | (*p)[1]);
printf("Calculated Auto CRC32: %8.8x\n", crc32.checksum());
*p = Spartan6Packet(crc32.checksum()); // current
packet is FDRI, next is Auto CRC
crc32.reset();
}
}
}
 
Someone pointed out to me that the necessary information can be inferred
from either of these files:

ISE/verilog/src/unisims/SIM_CONFIG_S6.v
ISE/vhdl/src/unisims/primitive/SIM_CONFIG_S6.vhd

Neil Steiner wrote:
I am unsuccessfully trying to update Spartan6 CRC checksums after I
make packet modifications. This is not a problem for
Virtex/E/2/2P/4/5/6/7 or for Spartan3E, but Spartan6 is a different
story altogether. I posted this same question on Xilinx Forums, but
there have been no responses.

I know that Spartan6 packets consist of 16-bit words, unlike the
32-bit words of the other architectures listed above. UG380 also
states that "The Cyclic Redundancy Check register utilizes a standard
32-bit CRC checksum algorithm." My perhaps incorrect assumption is
that the polynomial is the same CRC-32C (Castagnoli) polynomial as for
Virtex4/5/6/7 families. I am also assuming that only "payload words"
(after the packet header) factor into the calculation, just as with
the other architectures, and UG380 explicitly shows the address length
as 6 bits.

Does anybody know how to calculate this correctly for Spartan6? If
anyone cares to see the logic I'm trying to use, it's quite similar to
what works correctly for all the other Xilinx architectures:

// begin CRC calculation
uint32_t address = 0;
iterator p = begin();
iterator e = end();
// CRC-32C (Castagnoli) polynomial for Virtex4/5/6/7 families
boost::crc_basic<32> crc32(0x1edc6f41, 0, 0, false, true);
while(p < e) {
// look up the current packet
const Spartan6Packet& packet = *p++;
// only process write packets with non-zero payload length
if(!packet.isWrite()) continue;
address = packet.getAddress();
uint32_t wordCount = packet.getWordCount();
if(wordCount == 0) continue;
// CRC register write (this is what compares the expected and
supplied CRC values)
if(address == crcRegister) {
printf("Expected CRC32: %8.8x\n", (uint32_t(packet[1])
16) | packet[2]);
printf("Calculated CRC32: %8.8x\n", crc32.checksum());
*(p-1) = Spartan6Packet::makeType1Write(crcRegister,
crc32.checksum());
crc32.reset();
// reset CRC command
} else if(address == cmdRegister && wordCount >= 1 &&
packet[1] == rcrcCommand) {
crc32.reset();
// process packet contents
} else {
uint32_t j;
uint32_t mask;
for(uint32_t i = 1; i <= wordCount; i++) {
uint32_t word = packet;
//printf("Address: %4.4x\n", address);
//printf("Word: %8.8x\n", word);
for(j = 0, mask = 1; j < 16; j++, mask <<= 1) {
crc32.process_bit((word & mask) ? 1 : 0);
}
for(j = 0, mask = 1; j < addressLength; j++, mask <<= 1) {
crc32.process_bit((address & mask) ? 1 : 0);
}
}
// process the Auto CRC
if(autoCrc && address == fdriRegister) {
printf("Expected Auto CRC32: %8.8x\n",
(uint32_t((*p)[0]) << 16) | (*p)[1]);
printf("Calculated Auto CRC32: %8.8x\n",
crc32.checksum());
*p = Spartan6Packet(crc32.checksum()); // current
packet is FDRI, next is Auto CRC
crc32.reset();
}
}
}

 
If anybody is interested, this is the code that I inferred from the
simulation model. The rest of the code will be available in Torc. From
the testing that I've done it seems to work correctly. One interesting
deviation in Spartan6 compared to other architectures: The Auto-CRC
after the FDRI write does not reset the CRC.

/// \brief CRC class for the Spartan6 architecture.
struct CRC {
/// \brief Length of the CRC calculation.
enum { eLen = 22 };
/// \brief CRC calculation bits.
uint8_t mBits[eLen];
/// \brief CRC calculation value.
uint32_t mValue;
/// \brief Default constructor.
CRC(void) { reset(); }
/// \brief Function to clear the CRC calculation.
void reset(void) { for(int32_t i = 0; i < eLen; i++)
mBits = 0; mValue = 0; }
/// \brief Update the CRC with new data.
void update(uint32_t inAddress, uint32_t inWord) {
uint8_t input[eLen];
uint8_t next[eLen];
// initialize the input with the current register
address and data word
for(int32_t i = 21, mask = 0x20; i >= 16; i--, mask >>= 1)
input = (inAddress & mask) ? 1 : 0;
for(int32_t i = 15, mask = 0x8000; i >= 0; i--, mask
= 1)
input = (inWord & mask) ? 1 : 0;

// update the CRC
for(int32_t i = 21; i >= 16; i--) next = mBits[i -
1] ^ input;
next[15] = mBits[14] ^ input[15] ^ mBits[21];
for(int32_t i = 14; i >= 13; i--) next = mBits[i -
1] ^ input;
next[12] = mBits[11] ^ input[12] ^ mBits[21];
for(int32_t i = 11; i >= 8; i--) next = mBits[i - 1]
^ input;
next[7] = mBits[6] ^ input[7] ^ mBits[21];
for(int32_t i = 6; i >= 1; i--) next = mBits[i - 1]
^ input;
next[0] = input[0] ^ mBits[21];
// copy the updated bits into place
mValue = 0;
for(int32_t i = 0, mask = 1; i < eLen; i++, mask <<= 1) {
mBits = next;
mValue |= mBits ? mask : 0;
}
}
/// \brief Index operator.
uint8_t& operator[] (int i) { return mBits; }
/// \brief Cast operator to return the CRC as an integer.
operator uint32_t (void) const { return mValue; }
};

Neil Steiner wrote:
Someone pointed out to me that the necessary information can be
inferred from either of these files:

ISE/verilog/src/unisims/SIM_CONFIG_S6.v
ISE/vhdl/src/unisims/primitive/SIM_CONFIG_S6.vhd

Neil Steiner wrote:
I am unsuccessfully trying to update Spartan6 CRC checksums after I
make packet modifications. This is not a problem for
Virtex/E/2/2P/4/5/6/7 or for Spartan3E, but Spartan6 is a different
story altogether. I posted this same question on Xilinx Forums, but
there have been no responses.

I know that Spartan6 packets consist of 16-bit words, unlike the
32-bit words of the other architectures listed above. UG380 also
states that "The Cyclic Redundancy Check register utilizes a standard
32-bit CRC checksum algorithm." My perhaps incorrect assumption is
that the polynomial is the same CRC-32C (Castagnoli) polynomial as
for Virtex4/5/6/7 families. I am also assuming that only "payload
words" (after the packet header) factor into the calculation, just as
with the other architectures, and UG380 explicitly shows the address
length as 6 bits.

Does anybody know how to calculate this correctly for Spartan6? If
anyone cares to see the logic I'm trying to use, it's quite similar
to what works correctly for all the other Xilinx architectures:

// begin CRC calculation
uint32_t address = 0;
iterator p = begin();
iterator e = end();
// CRC-32C (Castagnoli) polynomial for Virtex4/5/6/7 families
boost::crc_basic<32> crc32(0x1edc6f41, 0, 0, false, true);
while(p < e) {
// look up the current packet
const Spartan6Packet& packet = *p++;
// only process write packets with non-zero payload length
if(!packet.isWrite()) continue;
address = packet.getAddress();
uint32_t wordCount = packet.getWordCount();
if(wordCount == 0) continue;
// CRC register write (this is what compares the expected and
supplied CRC values)
if(address == crcRegister) {
printf("Expected CRC32: %8.8x\n", (uint32_t(packet[1])
16) | packet[2]);
printf("Calculated CRC32: %8.8x\n", crc32.checksum());
*(p-1) = Spartan6Packet::makeType1Write(crcRegister,
crc32.checksum());
crc32.reset();
// reset CRC command
} else if(address == cmdRegister && wordCount >= 1 &&
packet[1] == rcrcCommand) {
crc32.reset();
// process packet contents
} else {
uint32_t j;
uint32_t mask;
for(uint32_t i = 1; i <= wordCount; i++) {
uint32_t word = packet;
//printf("Address: %4.4x\n", address);
//printf("Word: %8.8x\n", word);
for(j = 0, mask = 1; j < 16; j++, mask <<= 1) {
crc32.process_bit((word & mask) ? 1 : 0);
}
for(j = 0, mask = 1; j < addressLength; j++, mask <<=
1) {
crc32.process_bit((address & mask) ? 1 : 0);
}
}
// process the Auto CRC
if(autoCrc && address == fdriRegister) {
printf("Expected Auto CRC32: %8.8x\n",
(uint32_t((*p)[0]) << 16) | (*p)[1]);
printf("Calculated Auto CRC32: %8.8x\n",
crc32.checksum());
*p = Spartan6Packet(crc32.checksum()); // current
packet is FDRI, next is Auto CRC
crc32.reset();
}
}
}


 

Welcome to EDABoard.com

Sponsor

Back
Top