/* ---------------------------------------------------------------------------- */
/*                  Atmel Microcontroller Software Support                      */
/*                       SAM Software Package License                           */
/* ---------------------------------------------------------------------------- */
/* Copyright (c) 2015, Atmel Corporation                                        */
/*                                                                              */
/* All rights reserved.                                                         */
/*                                                                              */
/* Redistribution and use in source and binary forms, with or without           */
/* modification, are permitted provided that the following condition is met:    */
/*                                                                              */
/* - Redistributions of source code must retain the above copyright notice,     */
/* this list of conditions and the disclaimer below.                            */
/*                                                                              */
/* Atmel's name may not be used to endorse or promote products derived from     */
/* this software without specific prior written permission.                     */
/*                                                                              */
/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
/* ---------------------------------------------------------------------------- */

#ifndef _COMPILER_H_
#define _COMPILER_H_

#ifdef __rtems__
#include <bspopts.h>
#endif /* __rtems__ */
/*
 * Peripherals registers definitions
 */
#if defined __SAMV71J19__ \
	|| defined __SAMV71J20__ \
	|| defined __SAMV71J21__ \
	|| defined __SAMV71N19__ \
	|| defined __SAMV71N20__ \
	|| defined __SAMV71N21__ \
	|| defined __SAMV71Q19__ \
	|| defined __SAMV71Q20__ \
	|| defined __SAMV71Q21__
	#include "include/samv71/samv71.h"
#elif defined __SAMS70J19__ \
	|| defined __SAMS70J20__ \
	|| defined __SAMS70J21__ \
	|| defined __SAMS70N19__ \
	|| defined __SAMS70N20__ \
	|| defined __SAMS70N21__ \
	|| defined __SAMS70Q19__ \
	|| defined __SAMS70Q20__ \
	|| defined __SAMS70Q21__
	#include "include/sams70/sams70.h"
#elif defined __SAME70J19__ \
	|| defined __SAME70J20__ \
	|| defined __SAME70J21__ \
	|| defined __SAME70N19__ \
	|| defined __SAME70N20__ \
	|| defined __SAME70N21__ \
	|| defined __SAME70Q19__ \
	|| defined __SAME70Q20__ \
	|| defined __SAME70Q21__
	#include "include/same70/same70.h"
#else
	#error "please define correct macro for the chip first!"
#endif


//_____ D E C L A R A T I O N S ____________________________________________

#ifndef __ASSEMBLY__

#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

/* Define WEAK attribute */
#if defined   (__CC_ARM)
	#define WEAK __attribute__ ((weak))
#elif defined (__ICCARM__)
	#define WEAK __weak
#elif defined (__GNUC__)
	#define WEAK __attribute__ ((weak))
#endif

/* Define Compiler name of tool chains */
#if defined   (__CC_ARM)
	#define COMPILER_NAME               "KEIL"
#elif defined (__ICCARM__)
	#define COMPILER_NAME               "IAR"
#elif defined (__GNUC__)
	#define COMPILER_NAME               "GCC"
#endif

/* Define NO_INIT attribute */
#if defined   (__CC_ARM)
	#define NO_INIT
#elif defined (__ICCARM__)
	#define NO_INIT __no_init
#elif defined (__GNUC__)
	#define NO_INIT
#endif


/* Define memory sync for tool chains */
#if defined   (__CC_ARM)
	#define memory_sync()        __dsb(15);__isb(15);
#elif defined (__ICCARM__)
	#define memory_sync()        __DSB();__ISB();
#elif defined (__GNUC__)
	#define memory_sync()        __DSB();__ISB();
#endif

/* Define memory barrier for tool chains */
#if defined   (__CC_ARM)
	#define memory_barrier()        __dmb(15);
#elif defined (__ICCARM__)
	#define memory_barrier()        __DMB();
#elif defined (__GNUC__)
	#define memory_barrier()        __DMB();
#endif

/*! \name Token Paste
 *
 * Paste N preprocessing tokens together, these tokens being allowed to be \#defined.
 *
 * May be used only within macros with the tokens passed as arguments if the tokens are \#defined.
 *
 * For example, writing TPASTE2(U, WIDTH) within a macro \#defined by
 * UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is
 * equivalent to writing U32.
 */
//! @{
#define TPASTE2(a, b)                            a##b
#define TPASTE3(a, b, c)                         a##b##c
//! @}

/*! \name Absolute Token Paste
 *
 * Paste N preprocessing tokens together, these tokens being allowed to be \#defined.
 *
 * No restriction of use if the tokens are \#defined.
 *
 * For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined
 * as 32 is equivalent to writing U32.
 */
//! @{
#define ATPASTE2(a, b)                           TPASTE2(a, b)
#define ATPASTE3(a, b, c)                        TPASTE3(a, b, c)
//! @}


/**
 * \brief Emit the compiler pragma \a arg.
 *
 * \param arg The pragma directive as it would appear after \e \#pragma
 * (i.e. not stringified).
 */
#define COMPILER_PRAGMA(arg)            _Pragma(#arg)

/**
 * \def COMPILER_PACK_SET(alignment)
 * \brief Set maximum alignment for subsequent structure and union
 * definitions to \a alignment.
 */
#define COMPILER_PACK_SET(alignment)   COMPILER_PRAGMA(pack(alignment))

/**
 * \def COMPILER_PACK_RESET()
 * \brief Set default alignment for subsequent structure and union
 * definitions.
 */
#define COMPILER_PACK_RESET()          COMPILER_PRAGMA(pack())

/**
 * \brief Set user-defined section.
 * Place a data object or a function in a user-defined section.
 */
#if defined   (__CC_ARM)
	#define COMPILER_SECTION(a)    __attribute__((__section__(a)))
#elif defined (__ICCARM__)
	#define COMPILER_SECTION(a)    COMPILER_PRAGMA(location = a)
#elif defined (__GNUC__)
	#define COMPILER_SECTION(a)    __attribute__((__section__(a)))
#endif

/**
 * \brief Set aligned boundary.
 */
#if defined   (__CC_ARM)
	#define COMPILER_ALIGNED(a)    __attribute__((__aligned__(a)))
#elif defined (__ICCARM__)
	#define COMPILER_ALIGNED(a)    COMPILER_PRAGMA(data_alignment = a)
#elif defined (__GNUC__)
	#define COMPILER_ALIGNED(a)    __attribute__((__aligned__(a)))
#endif

/**
 * \brief Set word-aligned boundary.
 */

#if defined   (__CC_ARM)
	#define COMPILER_WORD_ALIGNED    __attribute__((__aligned__(4)))
#elif defined (__ICCARM__)
	#define COMPILER_WORD_ALIGNED    COMPILER_PRAGMA(data_alignment = 4)
#elif defined (__GNUC__)
	#define COMPILER_WORD_ALIGNED    __attribute__((__aligned__(4)))
#endif



/*! \name Mathematics
 *
 * The same considerations as for clz and ctz apply here but GCC does not
 * provide built-in functions to access the assembly instructions abs, min and
 * max and it does not produce them by itself in most cases, so two sets of
 * macros are defined here:
 *   - Abs, Min and Max to apply to constant expressions (values known at
 *     compile time);
 *   - abs, min and max to apply to non-constant expressions (values unknown at
 *     compile time), abs is found in stdlib.h.
 */
//! @{

/*! \brief Takes the absolute value of \a a.
 *
 * \param a Input value.
 *
 * \return Absolute value of \a a.
 *
 * \note More optimized if only used with values known at compile time.
 */
#define Abs(a)              (((a) <  0) ? -(a) : (a))

/*! \brief Takes the minimal value of \a a and \a b.
 *
 * \param a Input value.
 * \param b Input value.
 *
 * \return Minimal value of \a a and \a b.
 *
 * \note More optimized if only used with values known at compile time.
 */
#define Min(a, b)           (((a) < (b)) ?  (a) : (b))

/*! \brief Takes the maximal value of \a a and \a b.
 *
 * \param a Input value.
 * \param b Input value.
 *
 * \return Maximal value of \a a and \a b.
 *
 * \note More optimized if only used with values known at compile time.
 */
#define Max(a, b)           (((a) > (b)) ?  (a) : (b))

// abs() is already defined by stdlib.h

/*! \brief Takes the minimal value of \a a and \a b.
 *
 * \param a Input value.
 * \param b Input value.
 *
 * \return Minimal value of \a a and \a b.
 *
 * \note More optimized if only used with values unknown at compile time.
 */
#define min(a, b)   Min(a, b)

/*! \brief Takes the maximal value of \a a and \a b.
 *
 * \param a Input value.
 * \param b Input value.
 *
 * \return Maximal value of \a a and \a b.
 *
 * \note More optimized if only used with values unknown at compile time.
 */
#define max(a, b)   Max(a, b)

//! @}

#define  be32_to_cpu(x) __REV(x)
#define  cpu_to_be32(x) __REV(x)
#define  BE32_TO_CPU(x) __REV(x)
#define  CPU_TO_BE32(x) __REV(x)

/**
 * \def UNUSED
 * \brief Marking \a v as a unused parameter or value.
 */
#define UNUSED(v)          (void)(v)

/**
 * \weakgroup interrupt_group
 *
 * @{
 */

/**
 * \name Interrupt Service Routine definition
 *
 * @{
 */

/**
 * \brief Initialize interrupt vectors
 *
 * For NVIC the interrupt vectors are put in vector table. So nothing
 * to do to initialize them, except defined the vector function with
 * right name.
 *
 * This must be called prior to \ref irq_register_handler.
 */
#  define irq_initialize_vectors()   \
	do {                             \
	} while (0)

/**
 * \brief Register handler for interrupt
 *
 * For NVIC the interrupt vectors are put in vector table. So nothing
 * to do to register them, except defined the vector function with
 * right name.
 *
 * Usage:
 * \code
    irq_initialize_vectors();
    irq_register_handler(foo_irq_handler);
\endcode
 *
 * \note The function \a func must be defined with the \ref ISR macro.
 * \note The functions prototypes can be found in the device exception header
 *       files (exceptions.h).
 */
#  define irq_register_handler(int_num, int_prio)                      \
	NVIC_ClearPendingIRQ((IRQn_Type)int_num);                      \
	NVIC_SetPriority((IRQn_Type)int_num, int_prio);                \
	NVIC_EnableIRQ((IRQn_Type)int_num);                          \

	//@}


#  define cpu_irq_enable()                     \
	do {                                       \
		/*g_interrupt_enabled = true; */           \
		__DMB();                               \
		__enable_irq();                        \
	} while (0)
#  define cpu_irq_disable()                    \
	do {                                       \
		__disable_irq();                       \
		__DMB();                               \
		/*g_interrupt_enabled = false; */          \
	} while (0)

	typedef uint32_t irqflags_t;

#if !defined(__DOXYGEN__)
	extern volatile bool g_interrupt_enabled;
#endif

#define cpu_irq_is_enabled()    (__get_PRIMASK() == 0)

	static volatile uint32_t cpu_irq_critical_section_counter;
	static volatile bool     cpu_irq_prev_interrupt_state;

	static inline irqflags_t cpu_irq_save(void)
	{
		irqflags_t flags = cpu_irq_is_enabled();
		cpu_irq_disable();
		return flags;
	}

	static inline bool cpu_irq_is_enabled_flags(irqflags_t flags)
	{
		return (flags);
	}

	static inline void cpu_irq_restore(irqflags_t flags)
	{
		if (cpu_irq_is_enabled_flags(flags))
			cpu_irq_enable();
	}
	/*
	void cpu_irq_enter_critical(void);
	void cpu_irq_leave_critical(void);*/

	/**
	 * \weakgroup interrupt_deprecated_group
	 * @{
	 */

#define Enable_global_interrupt()            cpu_irq_enable()
#define Disable_global_interrupt()           cpu_irq_disable()
#define Is_global_interrupt_enabled()        cpu_irq_is_enabled()


	//_____ M A C R O S ________________________________________________________

	/*! \name Usual Constants
	 */
	//! @{
#define DISABLE   0
#define ENABLE    1
#define DISABLED  0
#define ENABLED   1
#define OFF       0
#define ON        1
#define FALSE     0
#define TRUE      1
#ifndef __cplusplus
	#if !defined(__bool_true_false_are_defined)
		#define false     FALSE
		#define true      TRUE
	#endif
#endif
#define KO        0
#define OK        1
#define PASS      0
#define FAIL      1
#define LOW       0
#define HIGH      1
#define CLR       0
#define SET       1
	//! @}

	/*! \brief Counts the trailing zero bits of the given value considered as a 32-bit integer.
	 *
	 * \param u Value of which to count the trailing zero bits.
	 *
	 * \return The count of trailing zero bits in \a u.
	 */
#define ctz(u)              ((u) & (1ul <<  0) ?  0 : \
							 (u) & (1ul <<  1) ?  1 : \
							 (u) & (1ul <<  2) ?  2 : \
							 (u) & (1ul <<  3) ?  3 : \
							 (u) & (1ul <<  4) ?  4 : \
							 (u) & (1ul <<  5) ?  5 : \
							 (u) & (1ul <<  6) ?  6 : \
							 (u) & (1ul <<  7) ?  7 : \
							 (u) & (1ul <<  8) ?  8 : \
							 (u) & (1ul <<  9) ?  9 : \
							 (u) & (1ul << 10) ? 10 : \
							 (u) & (1ul << 11) ? 11 : \
							 (u) & (1ul << 12) ? 12 : \
							 (u) & (1ul << 13) ? 13 : \
							 (u) & (1ul << 14) ? 14 : \
							 (u) & (1ul << 15) ? 15 : \
							 (u) & (1ul << 16) ? 16 : \
							 (u) & (1ul << 17) ? 17 : \
							 (u) & (1ul << 18) ? 18 : \
							 (u) & (1ul << 19) ? 19 : \
							 (u) & (1ul << 20) ? 20 : \
							 (u) & (1ul << 21) ? 21 : \
							 (u) & (1ul << 22) ? 22 : \
							 (u) & (1ul << 23) ? 23 : \
							 (u) & (1ul << 24) ? 24 : \
							 (u) & (1ul << 25) ? 25 : \
							 (u) & (1ul << 26) ? 26 : \
							 (u) & (1ul << 27) ? 27 : \
							 (u) & (1ul << 28) ? 28 : \
							 (u) & (1ul << 29) ? 29 : \
							 (u) & (1ul << 30) ? 30 : \
							 (u) & (1ul << 31) ? 31 : \
							 32)

#endif // __ASSEMBLY__

#endif  // _COMPILER_H_
