/*****************************************************************************
 * Copyright (c) 2003 Rowley Associates Limited.                             *
 *                                                                           *
 * This file may be distributed under the terms of the License Agreement     *
 * provided with this software.                                              *
 *                                                                           *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE   *
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
 *****************************************************************************/

#ifndef loader_h
#define loader_h

/*! \def ADDRESS_IN_RANGE(address, startAddress, endAddress)
    Macro to determine whether an address is within an address range.
*/
#define ADDRESS_IN_RANGE(address, startAddress, endAddress) ((address >= startAddress) && (address <= endAddress))

/*! \def RANGE_IN_RANGE(r1StartAddress, r1EndAddress, r2StartAddress, r2EndAddress)
    Macro to determine whether an address range is within another address range.
*/
#define RANGE_IN_RANGE(r1StartAddress, r1EndAddress, r2StartAddress, r2EndAddress) (ADDRESS_IN_RANGE(r1StartAddress, r2StartAddress, r2EndAddress) || ADDRESS_IN_RANGE(r1EndAddress, r2StartAddress, r2EndAddress))

/*! \def RANGE_OCCLUDES_RANGE(r1StartAddress, r1EndAddress, r2StartAddress, r2EndAddress)
    Macro to determine whether an address range overlaps another address range.
*/
#define RANGE_OCCLUDES_RANGE(r1StartAddress, r1EndAddress, r2StartAddress, r2EndAddress) (RANGE_IN_RANGE(r1StartAddress, r1EndAddress, r2StartAddress, r2EndAddress) || RANGE_IN_RANGE(r2StartAddress, r2EndAddress, r1StartAddress, r1EndAddress))

/*! \brief Initialise loader.
    This function is called prior to entering the loader's main loop in
    order to allow the loader to carry out any initialisation required.
    This function should be implemented when supporting a new loader target.
*/
void loaderBegin();

/*! \brief Terminate loader.
    This function is called on exit from the loader's main loop in
    order to allow the loader to carry out any termination required.
    This function should be implemented when supporting a new loader target.
*/
void loaderEnd();

/*! \brief Write a block of bytes.
    This function is called when the loader receives a poke operation.
    When called the data to poke must be read from the host using calls to
    \a loaderReadWord. The bytes are stored in each word in little endian
    order.
    This function should be implemented when supporting a new loader target.
    \param address The intial address to poke.
    \param length The number of bytes to poke.
    \return Non-zero on success.
*/
int loaderPoke(unsigned char *address, unsigned int length);

/*! \brief Write a value to a block of bytes.
    This function is called when the loader receives a memset operation.
    This function should be implemented when supporting a new loader target.
    \param address The initial address to set.
    \param length The number of bytes to set.
    \return Non-zero on success.
*/
int loaderMemset(unsigned char *address, unsigned int length,  unsigned char c);

/*! \brief Erase a block of non-volatile memory.
    This function is called when the loader receives an erase operation.
    This function should be implemented when supporting a new loader target.
    \param address The initial address to erase.
    \param length The number of bytes to erase.
    \return Non-zero on success.
*/
int loaderErase(unsigned char *address, unsigned int length);

/*! \brief Erase all non-volatile memory.
    This function is called when the loader receives an erase all operation.
    This function should be implemented when supporting a new loader target.
*/
int loaderEraseAll();

/*! \brief Set loader parameter.
    This function is called when the loader receives a set parameter operation.
    This function should be implemented when supporting a new loader target.
*/
int loaderSetParameter(unsigned int parameter, unsigned int value);

#ifdef LOADER_FLUSH_WRITES

/*! \brief Flush any outstanding writes.
    This function is called when the loader receives a peek, verify or CRC32
    operation and when the loader terminates in order to allow the loader to 
    finish off any outstanding writes.

    This function should be implemented when supporting a new loader target
    if the loader is built with the LOADER_FLUSH_WRITE definition defined.
*/
void loaderFlushWrites();

#endif

/*! \brief Wait for next command from host.
    This function is called by the loader main loop in order to wait for the
    next command from the host.
    This function can be re-imlemented to support a different loader
    communication scheme.
*/
void loaderWaitForCommand();

/*! \brief Read a word of data from the host.
    This function can be re-implemented to support a different loader 
    communication scheme.
    \return Data read from host.
*/
unsigned int loaderReadWord();

/*! \brief Write a word of data to the host.
    This function can be re-implemented to support a different loader
    communication scheme.
    \param v The data to write to the host.
*/
void loaderWriteWord(unsigned int v);

/*! \brief Return a pointer to block of read data.
    This function is only available in loader communication schemes that can
    read a block of data. It's intention is to allow loaders to improve
    performance by carrying out block operations when the type of communication
    scheme used by the loader is known.
    \return A pointer to the block of read data.
*/
unsigned int *loaderGetReadPtr();

/*! \brief Return a pointer to block of write data.
    This function is only available in loader communication schemes that can
    write a block of data. It's intention is to allow loaders to improve
    performance by carrying out block operations when the type of communication
    scheme used by the loader is known.
    \return A pointer to the location to write data.
*/
unsigned int *loaderGetWritePtr();

#endif
