
#include "TIBootChecksum.h"


// Tell the routine where the checksum is stored such that it can be
// compared with the calculated value.



typedef struct {
       UINT16 *firstAddr;
       UINT16 *lastAddr;
} MEMORY_BLOCK;


// The memory blocks to include in the checksum must
// be identified here.
//
// In the case of the F2810/12 boot ROM, the checksum
// skips over the blocks reserved to store the checksum
// itself.  Note that the pointers are to 16-bit values.
// This is because the routine itself will take care of
// the 32-bit addition using two 16-bit values.

#define NUMBLOCKS 2

MEMORY_BLOCK memblock[NUMBLOCKS] = {
       (UINT16 *)0x003FE000, (UINT16 *)0x003FFFBB,
       (UINT16 *)0x003FFFC0, (UINT16 *)0x003FFFFF
};



// This main function performs a very simple 64 bit checksum routine.
// 4 32-bit values are used to calculate the checksum.  This is done so that
// no overflow is lost.  After each addition, the value is checked to see if
// it has overflowed the lower 16-bits.  If it has, then the overflow portion
// in the upper 16-bits is added to the next most significant portion of the
// checksum.
//
// When the routine completes, the upper 16-bits of each portion of the checksum
// will be 0x000 - this portion should be discarded as it was only used to check
// for overflow and the checksum is then formed from the lower 16-bits.
//
// For example:
//     lowHalfLSW  = 0x00001111
//     lowHalfMSW  = 0x00002222
//     highHalfLSW = 0x00003333
//     highHalfMSW = 0x00004444
//
//     would result in a 64-bit checksum of 0x44443333 22221111

#define WDCR 0x7029

BOOLEAN Checksum(UINT64 * checksum)
{
      BOOLEAN result = FALSE;
      UINT16 errorCount = 0;
      UINT16 *currentVal;
      UINT16 *lastVal;
      UINT16 i;
      UINT16 count;

      count = 0;

      checksum->highHalfMSW = 0;
      checksum->highHalfLSW = 0;
      checksum->lowHalfLSW = 0;
      checksum->lowHalfMSW = 0;

    EALLOW;
    *(UINT16 *)WDCR = 0x68;
    EDIS;

    for(i = 0; i < NUMBLOCKS; i++) {

      currentVal = memblock[i].firstAddr;
      lastVal = memblock[i].lastAddr;


      // For each value in the block perform 32-bit addition.
      while(currentVal <= lastVal) {

          count++;

          // On C28x, the LSW of a 32-bit value is stored
          // in the lower memory address.  This portion of the
          // routine will add the LSW of the 32-bit value to
          // the checksum.  After the addition, each portion
          // is checked for overflow.  If overflow has occurred
          // then the overflow is added to the next most significant
          // word in the checksum.

          checksum->lowHalfLSW += *currentVal ^ ((unsigned long)currentVal & 0x0000FFFF);
          currentVal++;

          if(checksum->lowHalfLSW > 0xFFFF) {

              checksum->lowHalfMSW += checksum->lowHalfLSW >> 16;
              checksum->lowHalfLSW &= 0xFFFF;
          }

          if(checksum->lowHalfMSW > 0xFFFF) {

              checksum->highHalfLSW += checksum->lowHalfMSW >> 16;
              checksum->lowHalfMSW &= 0xFFFF;
          }

          if(checksum->highHalfLSW > 0xFFFF) {

              checksum->highHalfMSW += checksum->highHalfLSW >> 16;
              checksum->highHalfLSW &= 0xFFFF;
          }


          // On C28x, the MSW of a 32-bit value is stored
          // in the upper memory address.  This portion of the
          // routine will add the MSW of the 32-bit value to
          // the checksum.  Because it is the MSW it is added
          // to the lowerHalfMSW of the checksum. After
          // the addition, each portion is again checked for
          // overflow.  If overflow has occurred then
          // the overflow is added to the next most significant
          // word in the checksum.


          checksum->lowHalfMSW += *currentVal ^ ((unsigned long)currentVal & 0x0000FFFF);
          currentVal++;

//        checksum.lowHalfMSW += *currentVal++;

          if(checksum->lowHalfMSW > 0xFFFF) {

              checksum->highHalfLSW += checksum->lowHalfMSW >> 16;
              checksum->lowHalfMSW &= 0xFFFF;
          }

          if(checksum->highHalfLSW > 0xFFFF) {

              checksum->highHalfMSW += checksum->highHalfLSW >> 16;
              checksum->highHalfLSW &= 0xFFFF;
          }

       }
   }

   // Check that the calculated checksum is stored in memory
   // where it should be.   The checksum is stored in memory
   // in the following order
   //
   // low address:   lowHalfLSW
   //                lowHalfMSW
   //                highHalfLSW
   // high address:  highHalfMSW
   //

   currentVal = (UINT16 *)CHECKSUM_ADDR;
    if (*currentVal++ != (UINT16) checksum->lowHalfLSW)
    {
        errorCount++;
    }

    if (*currentVal++ != (UINT16) checksum->lowHalfMSW)
    {
        errorCount++;
    }
    if (*currentVal++ != (UINT16) checksum->highHalfLSW)
    {
        errorCount++;
    }
    if (*currentVal != (UINT16) checksum->highHalfMSW)
    {
        errorCount++;
    }


    if (errorCount == 0)
    {
        result = TRUE;
    }
    else
    {
        result = FALSE;
    }

   return result;

}



