/**********************************************************
 * Verifies the current firmware against the locally
 * stored original. This function assumes the firmware
 * has been written to target starting at address 0x00. 
 *
 * @param fwImage
 *    Pointer to locally stored copy of firmware image
 * 
 * @param size
 *    Size (in bytes) of firmware image
 * 
 * @returns 
 *    True if target firmware matches local copy. 
 *    False otherwise. 
 **********************************************************/
bool verifyFirmware(uint32_t *fwImage, uint32_t size)
{
  int i;
  int numWords = size / 4;
  bool ret = true;
  uint32_t value;
  uint32_t addr;
  uint32_t tarWrap =  getTarWrap();
  
  printf("Verifying firmware\n");
  
  /* Set autoincrement on TAR */
  writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT);
  
  for ( i=0; i<numWords; i++ ) 
  {   
    /* Get current address */
    addr = i*4;
        
    /* TAR must be initialized at every TAR wrap boundary
     * because the autoincrement wraps around at these */
    if ( (addr & tarWrap) == 0 )
    {
      writeAP(AP_TAR, addr);
      
      /* Do one dummy read. Subsequent reads will return the 
       * correct result. */
      readAP(AP_DRW, &value);
    }
    
    /* Read the value from addr */
    readAP(AP_DRW, &value);
    
    /* Verify that the read value matches what is expected */
    if ( value != fwImage[i] ) 
    {
      printf("Verification failed at address 0x%.8x\n", addr);
      printf("Value is 0x%.8x, should have been 0x%.8x\n", value, fwImage[i]);
      ret = false;
      break;
    }
  }
  
  /* Disable autoincrement on TAR */
  writeAP(AP_CSW, AP_CSW_DEFAULT);
     
  return ret;
}
/**********************************************************
 * Uploads and runs the flashloader on the target
 * The flashloader is written directly to the start
 * of RAM. Then the PC and SP are loaded from the
 * flashloader image. 
 **********************************************************/
void uploadFlashloader(uint32_t *flImage, uint32_t size)
{
  int w;
  uint32_t addr;
  uint32_t tarWrap;
  
  uint32_t numWords = size / 4;
  if ( numWords * 4 < size ) numWords++;
   
  resetAndHaltTarget();
  
  /* Get the TAR wrap-around period */
  tarWrap = getTarWrap();
  
  printf("Uploading flashloader\n");
  
  /* Enable autoincrement on TAR */
  writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT);
  
  for ( w=0; w<numWords; w++ ) 
  {
    /* Get address of current word */
    addr = RAM_START + w * 4;
    
    /* At the TAR wrap boundary we need to reinitialize TAR
     * since the autoincrement wraps at these */
    if ( (addr & tarWrap) == 0 )
    {
      writeAP(AP_TAR, addr);
    }
    
    writeAP(AP_DRW, flImage[w]);
  }
  
  writeAP(AP_CSW, AP_CSW_DEFAULT);
  
  printf("Booting flashloader\n");
  
  /* Load SP (Reg 13) from flashloader image */
  writeCpuReg(13, flImage[0]);
  
  /* Load PC (Reg 15) from flashloader image */
  writeCpuReg(15, flImage[1]);
    
  runTarget();
}
/**********************************************************
 * Writes a chunk of data to a buffer in the flashloader.
 * This function does not make any checks or assumptions.
 * It simply copies a number of words from the 
 * local to the remote buffer.
 * 
 * @param remoteAddr
 *    Address of the flashloader buffer at the target
 * 
 * @param localBuffer
 *    The local buffer to write from
 * 
 * @param numWords
 *    Number of words to write to buffer
 **********************************************************/
void writeToFlashloaderBuffer(uint32_t remoteAddr, uint32_t *localBuffer, int numWords)
{
    uint32_t bufferPointer = (uint32_t)remoteAddr;
    int curWord = 0;
    uint32_t tarWrap;

    /* Get the TAR wrap-around period */
    tarWrap = getTarWrap();
    
    /* Set auto increment on TAR to allow faster writes */
    writeAP(AP_CSW, AP_CSW_DEFAULT | AP_CSW_AUTO_INCREMENT);
    
    /* Initialize TAR with the start of buffer */
    writeAP(AP_TAR, bufferPointer);
    
    /* Send up to one full buffer of data */    
    while ( curWord < numWords )
    {
      /* At TAR wrap boundary we need to reinitialize TAR
       * since the autoincrement wraps at these */
      if ( (bufferPointer & tarWrap) == 0 )
      {
        writeAP(AP_TAR, bufferPointer);
      }
      
      /* Write one word */
      writeAP(AP_DRW, localBuffer[curWord]);
      
      /* Increment local and remote pointers */
      bufferPointer += 4;
      curWord += 1;
    }
            
    /* Disable auto increment on TAR */
    writeAP(AP_CSW, AP_CSW_DEFAULT);
}