This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AIS CRC calculation and operation

Other Parts Discussed in Thread: TMS320C6747, OMAP-L138

Referring to sprabb1b.pdf "Using the TMS320C6747/45/43 Bootloader" there is some pseudo-code for the CRC calculation. Code quoted at the end of this post for reference.  I think it has some errors.  Also I have some questions and comments about things that could be better documented.

1.  The decrement of bit_no needs to happen at the end of the while loops

2. In the incomplete last word processing, word = (word << remain * 8) >> remain * 8; the byte shift for padding should be (4 - remain),  not current 'remain'

3. In the crc calc crc = ((word >> bit_no) & 0x1) ^ (crc << 1); , the xor "^" can be replaced with a simple or "|"

I have verified that with changes 1..3, this generates the same CRC as the AISgen gui. (I haven't yet verifed that the bootloader actually accepts these CRCs...)

 

4. Note that the CRC is calculated over the ADDRESS and SIZE parameters of the section load command, plus all the data. (found this by trawling AISgen source code)

5. Note that this 'CRC' is not the same as the 'normal' CRC-32 calculation, which would append 32 zero bits to the end of the data and include those in the iteration. I.e. you can't use CRC-32 routines from a library to generate AIS CRCs.

6. For the Section Fill command, is the CRC calculated just over the parameters of the command as present in the AIS file and read from ROM, or also over the expanded data as filled into RAM?

7. Does the Validate CRC command also restart (zero initial crc for) the CRC calculation for subsequent section(s)? (apparently yes?)

8. Referring now to OMAP-L138_FlashAndBootUtils_2_30:

When an input section has a length not a multiple of 4 bytes, AISgen emits an AIS section load command with the size field rounded up to the next multiple of 4. The padding byte(s) are non-zero, (In my case it is one byte 0x25) and the CRC includes them.  But sprabb1b says "If the length of the section content is not a multiple of 4 bytes, appropriate zero padding is added to make it so; zero padding is not reflected in the SIZE argument."  I assume the CRC should only be calculated over SIZE  bytes, not including padding.

CRC calc from appendix C of sprabb1b:

// Process complete 32-bit words

for (size / 4)
{
  // Load a word from memory
  word = *dataPtr++;
  // Update CRC
  bit_no = 31;
  while (bit_no >= 0)
  {
    bit_no--;
    msb_bit = crc & 0x80000000;
    crc = ((word >> bit_no) & 0x1) ^ (crc << 1);
    if (msb_bit)
      crc ^= 0x04C11DB7;
  }
// CRC-32 polynomial
}
// Process incomplete last word if present
if (remain = size % 4)
{
  word = *dataPtr;
  // Pad incomplete word with zeros to make it complete
  word = (word << remain * 8) >> remain * 8;
  // Update CRC
  bit_no = 31;
  while (bit_no >= 0)
  {
    bit_no--;
    msb_bit = crc & 0x80000000;
    crc = ((word >> bit_no) & 0x1) ^ (crc << 1);
    if (msb_bit)   
      crc ^= 0x04C11DB7;
  }
// CRC-32 polynomial
}

 

  • Eliot,

    Here is correct code: 

    uint32_t crctest1 (uint32_t *dataPtr, uint32_t size, uint32_t crc)
    {
      uint32_t n;          /* CRC - 32 */
      uint32_t msb_bit;
      uint32_t word, remain;
      int bit_no;

      // data_ptr : Start address of current section (must be 4-byte aligned)
      // size : Size of current section (in bytes)
      // crc : Old crc (from earlier sections) or zero (for first section)
      // Process complete 32-bit words
      for (n = 0; n < (size >> 2); n++)
      {
        // Load a word from memory
        word = *dataPtr++;
        // Update CRC
        bit_no = 31;
        while (bit_no >= 0)
        {
          msb_bit = crc & 0x80000000;
          crc = ((word >> bit_no) & 0x1) ^ (crc << 1);
          if (msb_bit)
            crc ^= 0x04C11DB7; // CRC-32 polynomial
          bit_no--;
        }
      }

      // Process incomplete last word if present
      remain = size % 4;
      if (remain)
      {
        word = *dataPtr;
        // Pad incomplete word with zeros to make it complete
        word = (word << remain * 8) >> remain * 8;
        // Update CRC
        bit_no = 31;
        while (bit_no >= 0)
        {
          msb_bit = crc & 0x80000000;
          crc = ((word >> bit_no) & 0x1) ^ (crc << 1);
          if (msb_bit)
            crc ^= 0x04C11DB7; // CRC-32 polynomial
          bit_no--;
        }
      }

      return (crc);
    }

     

    It was noticed several months ago that this is wrong, and I thought it had been fixed, but it must have fallen through the cracks. It will get placed into the next document update.

    Regards, Daniel

  • EliotBlennerhassett said:

    4. Note that the CRC is calculated over the ADDRESS and SIZE parameters of the section load command, plus all the data. (found this by trawling AISgen source code)

    This was a recommendation we had already received and we recognize that it is useful info for those not using our provided AIS tools.

    EliotBlennerhassett said:

    5. Note that this 'CRC' is not the same as the 'normal' CRC-32 calculation, which would append 32 zero bits to the end of the data and include those in the iteration. I.e. you can't use CRC-32 routines from a library to generate AIS CRCs.

    You are correct, this is not a correct, standard CRC32.  This was corrected for the C6748/6/2 family of devices, but was not corrected in the C6747/5/3 family of devices to maintain proper backward compatibility with the original ROM boot loader.

    EliotBlennerhassett said:

    6. For the Section Fill command, is the CRC calculated just over the parameters of the command as present in the AIS file and read from ROM, or also over the expanded data as filled into RAM?

    The CRC is actually calculated over the three command parameters (size, type, and pattern word) and then the expanded fill data as it is in RAM.

    EliotBlennerhassett said:

    7. Does the Validate CRC command also restart (zero initial crc for) the CRC calculation for subsequent section(s)? (apparently yes?)

    Yes it does.

    EliotBlennerhassett said:

    8. Referring now to OMAP-L138_FlashAndBootUtils_2_30:

    When an input section has a length not a multiple of 4 bytes, AISgen emits an AIS section load command with the size field rounded up to the next multiple of 4. The padding byte(s) are non-zero, (In my case it is one byte 0x25) and the CRC includes them.  But sprabb1b says "If the length of the section content is not a multiple of 4 bytes, appropriate zero padding is added to make it so; zero padding is not reflected in the SIZE argument."  I assume the CRC should only be calculated over SIZE  bytes, not including padding.

    The data copied and the CRC value that the ROM expects should only be calculated over the data of the section size (the parameter in the Section Load command).  Any padding bytes stuck into the end of a section load payload will not be copied/loaded to the device memory and should not be used by the AISGen tool for CRC generation.  If the AISGen tool is including this data in the CRC generation, then this is a bug.

    Regards, Daniel

  • Thanks for all your answers Daniel, I'll verify your post.

    For the issue below, I don't need or expect anything to be fixed, so leave it to you to decide what if anything to do about it.

    Daniel Allred said:

    8. Referring now to OMAP-L138_FlashAndBootUtils_2_30:

    When an input section has a length not a multiple of 4 bytes, AISgen emits an AIS section load command with the size field rounded up to the next multiple of 4. The padding byte(s) are non-zero, (In my case it is one byte 0x25) and the CRC includes them.  But sprabb1b says "If the length of the section content is not a multiple of 4 bytes, appropriate zero padding is added to make it so; zero padding is not reflected in the SIZE argument."  I assume the CRC should only be calculated over SIZE  bytes, not including padding.

    The data copied and the CRC value that the ROM expects should only be calculated over the data of the section size (the parameter in the Section Load command).  Any padding bytes stuck into the end of a section load payload will not be copied/loaded to the device memory and should not be used by the AISGen tool for CRC generation.  If the AISGen tool is including this data in the CRC generation, then this is a bug.

    Regards, Daniel

    [/quote]

    I haven't (and don't plan to) work through AISgen's process from loading COFF to generating CRC to see where the problem starts. i.e. where the size gets padded to N*4.  I observed the problem when I was getting my aisgen output to match the TI AISgen gui output and input file contained a .const section with odd length (perhaps an odd length string came last in the link).

    AISgen does calculate the correct CRC given the Section Load parameters and the data in the AIS image, so the section will still load and verify correctly.

    The fact that the padding bytes are non-zero makes me think that they could well be junk data that is different with different versions of the software, or on different PCs, which would lead to the same input coff file producing differing AIS files, maybe a problem for verification.

    regards

    Eliot

  • Daniel Allred said:

    Eliot,

    Here is correct code: 

      remain = size % 4;
      if (remain)
      {
        word = *dataPtr;
        // Pad incomplete word with zeros to make it complete
        word = (word << remain * 8) >> remain * 8;

    This part is still "wrong".  If remain == 3, then 24 bits of word are shifted out, and zeros shifted back in their place.  So 16 data bits would not be checked.

    I put "wrong" in quotes, because if this is actually implemented this way in the ROM bootloader, then it is the "right" way to generate a CRC that will verify correctly.

    Please let me know is this code "right" or "wrong".

    --

    Eliot

     

  • EliotBlennerhassett said:

    Eliot,

    Here is correct code: 

      remain = size % 4;
      if (remain)
      {
        word = *dataPtr;
        // Pad incomplete word with zeros to make it complete
        word = (word << remain * 8) >> remain * 8;

    This part is still "wrong".  If remain == 3, then 24 bits of word are shifted out, and zeros shifted back in their place.  So 16 data bits would not be checked.

    [/quote]

    Eliot,

    You are "right", this code "wrong".  This is not what the ROM does, so the ROM is also "right".

    Here is actual correct code: 

      remain = size % 4;
      if (remain)
      {
        word = *dataPtr;
        // Pad incomplete word with zeros to make it complete
        word = (word << (4-remain) * 8) >> (4-remain) * 8;

    This matches the ROM boot loader. Note this code was not from the ROM itself, but from a test program I wrote when it was previously pointed out that the psuedocode in the appnote was wrong. But I guess we never checked the test code against an actual section of non-word-aligned size. Thanks for pointing this out.

    Regards, Daniel

  • Hi Daniel,

    now that you have answered my questions about the CRC,  I can generate correct AIS (at least for d800k002 ROM). 

    I'd like to share my scripts (currently about 400 lines of python) in case they may be useful to others - is there an appropriate place on the wiki or forum that I should do this?  Or should I just publish via one of the online repos e.g. github?

    regards

    Eliot

  • Eliot,

    Glad to hear it.  I would definitely recommend creating a wiki page entry on the TI embedded processor wiki.  I would suggest linking to the "OMAPL1x_Topic_Boot" category.

    For such a small bit of code, you host it on the wiki itself, but you could just link from the wiki to an online repo if you want to keep it under source control.

    Regards, Daniel

  • Well...it been two years and the TRMs are still wrong. This thread has been been very helpful with my attempts to do the same with the C6748. Thanks for that. Not so happy that the C6748 CRC is not fixed. The C6748 CRC algorithm does not appear to append 32-bits of zeroes to the end of data. Other quirks. Started a new thread here:

    http://e2e.ti.com/support/dsp/tms320c6000_high_performance_dsps/f/115/t/283656.aspx