/**
 * \file IfxCpu_IntrinsicsTasking.h
 *
 * \version iLLD_1_0_1_11_0
 * \copyright Copyright (c) 2019 Infineon Technologies AG. All rights reserved.
 *
 *
 *
 *                                 IMPORTANT NOTICE
 *
 *
 * Use of this file is subject to the terms of use agreed between (i) you or 
 * the company in which ordinary course of business you are acting and (ii) 
 * Infineon Technologies AG or its licensees. If and as long as no such 
 * terms of use are agreed, use of this file is subject to following:


 * Boost Software License - Version 1.0 - August 17th, 2003

 * Permission is hereby granted, free of charge, to any person or 
 * organization obtaining a copy of the software and accompanying 
 * documentation covered by this license (the "Software") to use, reproduce,
 * display, distribute, execute, and transmit the Software, and to prepare
 * derivative works of the Software, and to permit third-parties to whom the 
 * Software is furnished to do so, all subject to the following:

 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer, must
 * be included in all copies of the Software, in whole or in part, and all
 * derivative works of the Software, unless such copies or derivative works are
 * solely in the form of machine-executable object code generated by a source
 * language processor.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.

 *
 * \defgroup IfxLld_Cpu_Intrinsics_Tasking Intrinsics for TASKING compiler
 * \ingroup IfxLld_Cpu_Intrinsics
 *
 */
#ifndef IFXCPU_INTRINSICSTASKING_H
#define IFXCPU_INTRINSICSTASKING_H
/******************************************************************************/
#include "Ifx_Types.h"
/******************************************************************************/
/* *INDENT-OFF* */

#ifndef __cplusplus
/** Function call without return
 */
#define Ifx__non_return_call(fun)	__asm("\tji %0"::"a"(fun))

/** Jump and link
 */
IFX_INLINE void Ifx__jump_and_link(void (*fun)(void))
{
	__asm("jli %0"::"a"(fun));
}

IFX_INLINE void Ifx__moveToDataParam0(unsigned int var)
{
	__asm("mov d4, %0"::"d"(var));
}

IFX_INLINE void Ifx__moveToAddrParam0(const void *var)
{
	__asm("mov.aa a4, %0"::"a"(var));
}

IFX_INLINE unsigned int Ifx__getDataParamRet(void)
{
	unsigned int var;
	__asm(" mov\t %0, d2":"=d"(var));
	return var;
}

IFX_INLINE void Ifx__moveToDataParamRet(unsigned int var)
{
	__asm("mov d2, %0"::"d"(var));
}

IFX_INLINE void Ifx__jumpToFunction(const void *fun)
{
	Ifx__non_return_call(fun);
}

IFX_INLINE void Ifx__jumpToFunctionWithLink(const void *fun)
{
	Ifx__jump_and_link((void (*)(void))fun);
}

IFX_INLINE void Ifx__jumpBackToLink(void)
{
	__asm("ji a11");
}
#endif
/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_any_type Cross type arithmetic operation
 *
 * Macro compatible with float, fix point, signed integer and unsigned integer
 *
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__minX(X,Y)                     ( ((X) < (Y)) ? (X) : (Y) )
#define Ifx__maxX(X,Y)                     ( ((X) > (Y)) ? (X) : (Y) )
#define Ifx__saturateX(X,Min,Max)          ( Ifx__minX(Ifx__maxX(X, Min), Max) )
#define Ifx__checkrangeX(X,Min,Max)        (((X) >= (Min)) && ((X) <= (Max)))
/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_singed_integer Signed integer operation
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__saturate(X,Min,Max)           ( __min(__max(X, Min), Max) )
/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_unsinged_integer Unsigned integer operation
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__saturateu(X,Min,Max)           ( __minu(__maxu(X, Min), Max) )
/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_float Floating point operation
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__checkrange(X,Min,Max)         (((X) >= (Min)) && ((X) <= (Max)))

#define Ifx__sqrf(X)                       ((X) * (X))
#define Ifx__sqrtf(X)                      sqrtf(X)

#define Ifx__roundf(X)                     ((((X) - (int)(X)) > 0.5) ? (1 + (int)(X)) : ((int)(X)))
#define Ifx__absf(X)                       ( ((X) < 0.0) ? -(X) : (X) )
#define Ifx__minf(X,Y)                     ( ((X) < (Y)) ? (X) : (Y) )
#define Ifx__maxf(X,Y)                     ( ((X) > (Y)) ? (X) : (Y) )
#define Ifx__saturatef(X,Min,Max)          ( Ifx__minf(_Ifx_maxf(X, Min), Max) )
#define Ifx__checkrangef(X,Min,Max)        (((X) >= (Min)) && ((X) <= (Max)))

#define Ifx__abs_stdreal(X)                ( ((X) > 0.0) ? (X) : -(X) )
#define Ifx__min_stdreal(X,Y)              ( ((X) < (Y)) ? (X) : (Y) )
#define Ifx__max_stdreal(X,Y)              ( ((X) > (Y)) ? (X) : (Y) )
#define Ifx__saturate_stdreal(X,Min,Max)   ( Ifx__min_stdreal(Ifx__max_stdreal(X, Min), Max) )

#define Ifx__neqf(X,Y)                     ( ((X) > (Y)) ||  ((X) < (Y)) )     /**< X != Y */
#define Ifx__leqf(X,Y)                     ( !((X) > (Y)) )     /**< X <= Y */
#define Ifx__geqf(X,Y)                     ( !((X) < (Y)) )     /**< X >= Y */
/** \} */
/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_fractional Fractional Arithmetic Support
 The next table provides an overview of intrinsic functions to convert fractional values. Note that the
 TASKING VX-toolset C compiler for TriCore fully supports the fractional type so normally you should not
 need these intrinsic functions (except for __mulfractlong). For compatibility reasons the TASKING C
 compiler does support these functions.
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__fract_to_float(value)  ((float)(value))

#define Ifx__mulfractlong __mulfractlong

#define Ifx__mulfractfract(fractvalue1,fractvalue2)  ((fractvalue1)*(fractvalue2))

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_insert Insert / Extract Bit-fields and Bits
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */

#define Ifx__extru(a, p, w)            __extru(a,p,w)

#define Ifx__extr(a, p, w)             __extr(a,p,w)

#define Ifx__imaskldmst(a, v, b, p)    __imaskldmst((int*)a, v, b, p)

#define Ifx__insert(a,b,p,w)           __insert(a,b,p,w)

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_interrupt_handling Interrupt Handling
 The next table provides an overview of the intrinsic functions to read or set interrupt handling.
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__disable_and_save __disable_and_save

#define Ifx__restore __restore

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_miscellaneous Miscellaneous Intrinsic Functions
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_packed Packed Data Type Support
 The next table provides an overview of the intrinsic functions for initialization of packed data type.
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */

/** \} */

#ifndef __cplusplus
/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_register Register Handling
 The next table provides an overview of the intrinsic functions that you can use to access control registers.
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */
#define Ifx__mtcr_no_isync(reg, val)   \
    __asm("mtcr %0,%1"::"i"(reg),"d"(val));

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_saturation Saturation Arithmetic Support
 These intrinsics support saturation arithmetic
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */

#define Ifx__adds(a,b)                 ((__sat int)(a)+(__sat int)(b))

#define Ifx__addsu(a,b)                ((__sat unsigned int)(a)+(__sat unsigned int)(b))

#define Ifx__subs(a,b)                 ((__sat int)(a)-(__sat int)(b))

#define Ifx__subsu(a,b)                ((__sat unsigned int )(a)-(__sat unsigned int )(b))

/** \} */

/** \defgroup IfxLld_Cpu_Intrinsics_Tasking_single_assembly Insert Single Assembly Instruction
 The next table provides an overview of the intrinsic functions that you can use to insert a single assembly
 instruction.You can also use inline assembly but these intrinsics provide a shorthand for frequently used
 assembly instructions.
 * \ingroup IfxLld_Cpu_Intrinsics_Tasking
 * \{
 */

IFX_INLINE void Ifx__nops(void* cnt)
{
    __asm("nop16 \n\t"
          "loop %0,*-2"
          ::"a"(((char*)cnt) - 1));
}

#define Ifx__NOP(n)   __asm(".DUP " #n "\n\tnop16\n\t.ENDM\n")

/** Insert a memory barrier
 */
#define Ifx__mem_barrier __asm("":::"memory");

#if CPU_NO_LDMST
IFX_INLINE void Ifx__ldmstC(volatile void *addr, uint32 mask, uint32 data)
{
    *(volatile uint32 *)addr = (*(volatile uint32 *)addr & ~mask) | (mask & data);
}

#define Ifx__ldmst(a,b,c) Ifx__ldmstC(a,b,c)
#else

IFX_INLINE void Ifx__ldmstAsm(volatile void *addr, uint32 mask, uint32 data)
{
    __asm("\tmov d3, %1 \n"
          "\tmov d2, %2 \n"
          "\tldmst [%0],e2"
          ::"a"(addr), "d"(mask), "d"(data):"d2", "d3");

}

/** Convert float to fract
 */
IFX_INLINE fract Ifx__float_to_fract(float a)
{
    fract res;
    __asm("ftoq31  %0,%1,%2":"=d"(res):"d"(a), "d"(0):"memory");
    return res;
}

#define Ifx__fract_to_sfract __round16

/** Convert float to sfract
 */
IFX_INLINE sfract Ifx__float_to_sfract(float a)
{
    fract tmp = Ifx__float_to_fract(a);
    return Ifx__fract_to_sfract(tmp);
}

#define Ifx__ldmst(addr, mask, data) Ifx__ldmstAsm(addr, mask, data)
#endif

IFX_INLINE void Ifx__stopPerfCounters(void)
{ //__mtcr (CPU_CCTRL, 0);
    __asm(
            "    mov d0,#0\n"
            "    mtcr #0xFC00,d0\n"
            "    isync\n"
            :::"d0");
}

/** \} */

/* FIXME use inline instead of #define */
/* FIXME is it really required to have #define __setareg(areg,val) ___setareg(areg,val) or can __setareg() implemented directly */
#define Ifx___setareg(areg,val) \
    { __asm (" movh.a\t "#areg",#@his("#val")\n lea\t "#areg",["#areg"]@los("#val")"); }
#define Ifx__setareg(areg,val) Ifx___setareg(areg,val)

/** \brief This function is a implementation of a binary semaphore using compare and swap instruction
 * \param address address of resource.
 * \param value This variable is updated with status of address
 * \param condition if the value of address matches with the value of condition, then swap of value & address occurs.
 *
 */
#define  Ifx__cmpAndSwap(address,value,condition) \
     __cmpswapw((address), ((unsigned long)value), (condition) )

/** \brief Convert a fixpoint value to float32
 *
 * This function converts a value from a fixpoint format to a float32 format.
 *
 *
 * \param value value to be converted.
 * \param shift position of the fix point. Range = [-256, 255] => (Qx.y format where x = shift+1).
 *
 * \return Returns the converted value in the float32 format.
 *
 */
IFX_INLINE float32 Ifx__fixpoint_to_float32(fract value, sint32 shift)
{
    float32 result;

    __asm(
        "   q31tof\t%0, %1, %2  \n"
        : "=d" (result)
        : "d" (value), "d" (shift));
    return result;
}

IFX_INLINE void* Ifx__getA11(void)
{
    unsigned int *res;
    __asm("mov.aa %0, a11": "=a" (res) : :"a11");
    return res;
}

IFX_INLINE void Ifx__setStackPointer(void *stackAddr)
{
    __asm("mov.aa a10, %0": : "a" (stackAddr) :"a10");
}

IFX_INLINE uint32 IfxCpu_calculateCrc32(uint32 *startaddress, uint8 length) 
{
    uint32 returnvalue;
    __asm("MOV d0, #0x0"); /* set seed value to 0 */
    for (;length > 0; length--) 
    { 
        /*calculate the CRC over all data */
        __asm("MOV d1,%0" : : "d" (*startaddress)); 
        __asm("CRC32 d0,d0,d1"); 
        startaddress++; 
    } 
    __asm("MOV %0,d0" : "=d" (returnvalue)); /* return result of CRC*/
    return returnvalue;
}

IFX_INLINE uint32 IfxCpu_getRandomVal(uint32 a, uint32 x, uint32 m)
{
	uint32 result;
    __asm("      mul.u     e14,%1,%2      ; d15 = Eh; d14 = El    \n"
        "        mov       d12,d14        ;   e12 = El            \n"
        "        mov       d13,#0         ;                       \n"
        "        madd.u    e14,e12,d15,#5 ; e14 = El + 5 * d15    \n"
        " 1:     jge.u     d14,%3,2n      ;                       \n"
        "        jz        d15,3n         ;                       \n"
        " 2:     subx      d14,d14,%3     ;  e12=e12-m            \n"
        "        subc      d15,d15,d13    ; d13=d13-0             \n"
        "        loopu     1p             ;                       \n"
        " 3:     mov       %0,d14         ;                       \n"
        : "=d"(result) : "d"(a), "d"(x), "d"(m) : "e14","e12");
    return result;
}

IFX_INLINE sint32 Ifx__popcnt(sint32 a)
{ 
	sint32 res; 
	__asm("popcnt %0,%1":"=d"(res):"d"(a)); 
		return res; 
}
#endif

/* Macros for backward compatibility of the intrinsics*/
/******************************************************************************/
#ifndef IFX_CFG_DISABLE_DEFAULT_INTRINSICS
#ifndef __non_return_call
#define __non_return_call Ifx__non_return_call
#endif

#ifndef __jump_and_link
#define __jump_and_link Ifx__jump_and_link
#endif

#ifndef __moveToDataParam0
#define __moveToDataParam0 Ifx__moveToDataParam0
#endif

#ifndef __moveToAddrParam0
#define __moveToAddrParam0 Ifx__moveToAddrParam0
#endif

#ifndef __getDataParamRet
#define __getDataParamRet Ifx__getDataParamRet
#endif

#ifndef __moveToDataParamRet
#define __moveToDataParamRet Ifx__moveToDataParamRet
#endif

#ifndef __jumpToFunction
#define __jumpToFunction Ifx__jumpToFunction
#endif

#ifndef __jumpToFunctionWithLink
#define __jumpToFunctionWithLink Ifx__jumpToFunctionWithLink
#endif

#ifndef __jumpBackToLink
#define __jumpBackToLink Ifx__jumpBackToLink
#endif

#ifndef __minX
#define __minX Ifx__minX
#endif

#ifndef __maxX
#define __maxX Ifx__maxX
#endif

#ifndef __saturateX
#define __saturateX Ifx__saturateX
#endif

#ifndef __checkrangeX
#define __checkrangeX Ifx__checkrangeX
#endif

#ifndef __saturate
#define __saturate Ifx__saturate
#endif

#ifndef __saturateu
#define __saturateu Ifx__saturateu
#endif

#ifndef __checkrange
#define __checkrange Ifx__checkrange
#endif

#ifndef __sqrtf
#define __sqrtf Ifx__sqrtf
#endif

#ifndef __sqrf
#define __sqrf Ifx__sqrf
#endif

#ifndef __roundf
#define __roundf Ifx__roundf
#endif

#ifndef __absf
#define __absf Ifx__absf
#endif

#ifndef __maxf
#define __maxf Ifx__maxf
#endif

#ifndef __saturatef
#define __saturatef Ifx__saturatef
#endif

#ifndef __minf
#define __minf Ifx__minf
#endif

#ifndef __checkrangef
#define __checkrangef Ifx__checkrangef
#endif

#ifndef __abs_stdreal
#define __abs_stdreal Ifx__abs_stdreal
#endif

#ifndef __saturate_stdreal
#define __saturate_stdreal Ifx__saturate_stdreal
#endif

#ifndef __min_stdreal
#define __min_stdreal Ifx__min_stdreal
#endif

#ifndef __max_stdreal
#define __max_stdreal Ifx__max_stdreal
#endif

#ifndef __neqf
#define __neqf Ifx__neqf
#endif

#ifndef __leqf
#define __leqf Ifx__leqf
#endif

#ifndef __geqf
#define __geqf Ifx__geqf
#endif

#ifndef __fract_to_float
#define __fract_to_float Ifx__fract_to_float
#endif

#ifndef __mulfractlong
#define __mulfractlong Ifx__mulfractlong
#endif

#ifndef __mulfractfract
#define __mulfractfract Ifx__mulfractfract
#endif

#ifndef __disable_and_save
#define __disable_and_save Ifx__disable_and_save
#endif

#ifndef __restore
#define __restore Ifx__restore
#endif

#ifndef __mtcr_no_isync
#define __mtcr_no_isync Ifx__mtcr_no_isync
#endif

#ifndef __adds
#define __adds Ifx__adds
#endif

#ifndef __addsu
#define __addsu Ifx__addsu
#endif

#ifndef __subs
#define __subs Ifx__subs
#endif

#ifndef __subsu
#define __subsu Ifx__subsu
#endif

#ifndef __nops
#define __nops Ifx__nops
#endif

#if ((!defined(NOP)) && (!defined(IFX_CFG_DISABLE_DEFAULT_INTRINSICS)))
#define NOP Ifx__NOP
#endif

#ifndef __mem_barrier
#define __mem_barrier Ifx__mem_barrier
#endif

#ifndef __ldmst
#define __ldmst Ifx__ldmst
#endif

#ifndef __ldmstC
#define __ldmstC Ifx__ldmstC
#endif

#ifndef __float_to_sfract
#define __float_to_sfract Ifx__float_to_sfract
#endif

#ifndef __float_to_fract
#define __float_to_fract Ifx__float_to_fract
#endif

#ifndef __fract_to_sfract
#define __fract_to_sfract Ifx__fract_to_sfract
#endif

#ifndef __ldmstAsm
#define __ldmstAsm Ifx__ldmstAsm
#endif

#ifndef __stopPerfCounters
#define __stopPerfCounters Ifx__stopPerfCounters
#endif

#ifndef __setareg
#define __setareg Ifx__setareg
#endif

#ifndef ___setareg
#define ___setareg Ifx___setareg
#endif

#ifndef __cmpAndSwap
#define __cmpAndSwap Ifx__cmpAndSwap
#endif

#ifndef __fixpoint_to_float32
#define __fixpoint_to_float32 Ifx__fixpoint_to_float32
#endif

#ifndef __getA11
#define __getA11 Ifx__getA11
#endif

#ifndef __setStackPointer
#define __setStackPointer Ifx__setStackPointer
#endif

#ifndef __popcnt
#define __popcnt Ifx__popcnt
#endif

#endif
/******************************************************************************/
/* *INDENT-ON* */
/******************************************************************************/
#endif /* IFXCPU_INTRINSICSTASKING_H */
