448 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			448 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *   http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| /******************************************************************************
 | |
|  * @file     csi_instr.h
 | |
|  * @brief    CSI Header File for instruct.
 | |
|  * @version  V1.0
 | |
|  * @date     02. June 2017
 | |
|  ******************************************************************************/
 | |
| 
 | |
| #ifndef _CSI_INSTR_H_
 | |
| #define _CSI_INSTR_H_
 | |
| 
 | |
| 
 | |
| #define __CSI_GCC_OUT_REG(r) "=r" (r)
 | |
| #define __CSI_GCC_USE_REG(r) "r" (r)
 | |
| 
 | |
| /**
 | |
|   \brief   No Operation
 | |
|   \details No Operation does nothing. This instruction can be used for code alignment purposes.
 | |
|  */
 | |
| __ALWAYS_INLINE void __NOP(void)
 | |
| {
 | |
|     __ASM volatile("nop");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Wait For Interrupt
 | |
|   \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.
 | |
|  */
 | |
| __ALWAYS_INLINE void __WFI(void)
 | |
| {
 | |
|     __ASM volatile("wait");
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Wait For Interrupt
 | |
|   \details Wait For Interrupt is a hint instruction that suspends execution until one interrupt occurs.
 | |
|  */
 | |
| __ALWAYS_INLINE void __WAIT(void)
 | |
| {
 | |
|     __ASM volatile("wait");
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Doze For Interrupt
 | |
|   \details Doze For Interrupt is a hint instruction that suspends execution until one interrupt occurs.
 | |
|  */
 | |
| __ALWAYS_INLINE void __DOZE(void)
 | |
| {
 | |
|     __ASM volatile("doze");
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Stop For Interrupt
 | |
|   \details Stop For Interrupt is a hint instruction that suspends execution until one interrupt occurs.
 | |
|  */
 | |
| __ALWAYS_INLINE void __STOP(void)
 | |
| {
 | |
|     __ASM volatile("stop");
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Instruction Synchronization Barrier
 | |
|   \details Instruction Synchronization Barrier flushes the pipeline in the processor,
 | |
|            so that all instructions following the ISB are fetched from cache or memory,
 | |
|            after the instruction has been completed.
 | |
|  */
 | |
| __ALWAYS_INLINE void __ISB(void)
 | |
| {
 | |
|     __ASM volatile("sync"::: "memory");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Data Synchronization Barrier
 | |
|   \details Acts as a special kind of Data Memory Barrier.
 | |
|            It completes when all explicit memory accesses before this instruction complete.
 | |
|  */
 | |
| __ALWAYS_INLINE void __DSB(void)
 | |
| {
 | |
|     __ASM volatile("sync"::: "memory");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Data Memory Barrier
 | |
|   \details Ensures the apparent order of the explicit memory operations before
 | |
|            and after the instruction, without ensuring their completion.
 | |
|  */
 | |
| __ALWAYS_INLINE void __DMB(void)
 | |
| {
 | |
|     __ASM volatile("sync"::: "memory");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Reverse byte order (32 bit)
 | |
|   \details Reverses the byte order in integer value.
 | |
|   \param [in]    value  Value to reverse
 | |
|   \return               Reversed value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __REV(uint32_t value)
 | |
| {
 | |
|     return __builtin_bswap32(value);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Reverse byte order (16 bit)
 | |
|   \details Reverses the byte order in two unsigned short values.
 | |
|   \param [in]    value  Value to reverse
 | |
|   \return               Reversed value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __REV16(uint32_t value)
 | |
| {
 | |
|     uint32_t result;
 | |
| #if (__CK80X >= 2)
 | |
|     __ASM volatile("revh %0, %1" : __CSI_GCC_OUT_REG(result) : __CSI_GCC_USE_REG(value));
 | |
| #else
 | |
|     result = ((value & 0xFF000000) >> 8) | ((value & 0x00FF0000) << 8) |
 | |
|              ((value & 0x0000FF00) >> 8) | ((value & 0x000000FF) << 8);
 | |
| #endif
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Reverse byte order in signed short value
 | |
|   \details Reverses the byte order in a signed short value with sign extension to integer.
 | |
|   \param [in]    value  Value to reverse
 | |
|   \return               Reversed value
 | |
|  */
 | |
| __ALWAYS_INLINE int32_t __REVSH(int32_t value)
 | |
| {
 | |
|     return (short)(((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8));
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Rotate Right in unsigned value (32 bit)
 | |
|   \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.
 | |
|   \param [in]    op1  Value to rotate
 | |
|   \param [in]    op2  Number of Bits to rotate
 | |
|   \return               Rotated value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
 | |
| {
 | |
|     return (op1 >> op2) | (op1 << (32U - op2));
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Breakpoint
 | |
|   \details Causes the processor to enter Debug state
 | |
|            Debug tools can use this to investigate system state when the instruction at a particular address is reached.
 | |
|  */
 | |
| __ALWAYS_INLINE void __BKPT()
 | |
| {
 | |
|     __ASM volatile("bkpt");
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Reverse bit order of value
 | |
|   \details Reverses the bit order of the given value.
 | |
|   \param [in]    value  Value to reverse
 | |
|   \return               Reversed value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __RBIT(uint32_t value)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
| #if       (__CK80X >= 0x03U)
 | |
|     __ASM volatile("brev %0, %1" : "=r"(result) : "r"(value));
 | |
| #else
 | |
|     int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */
 | |
| 
 | |
|     result = value;                      /* r will be reversed bits of v; first get LSB of v */
 | |
| 
 | |
|     for (value >>= 1U; value; value >>= 1U)
 | |
|     {
 | |
|         result <<= 1U;
 | |
|         result |= value & 1U;
 | |
|         s--;
 | |
|     }
 | |
| 
 | |
|     result <<= s;                        /* shift when v's highest bits are zero */
 | |
| #endif
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   Count leading zeros
 | |
|   \details Counts the number of leading zeros of a data value.
 | |
|   \param [in]  value  Value to count the leading zeros
 | |
|   \return             number of leading zeros in value
 | |
|  */
 | |
| #define __CLZ             __builtin_clz
 | |
| /**
 | |
|   \details This function saturates a signed value.
 | |
|   \param [in]    x   Value to be saturated
 | |
|   \param [in]    y   Bit position to saturate to [1..32]
 | |
|   \return            Saturated value.
 | |
|  */
 | |
| __ALWAYS_INLINE int32_t __SSAT(int32_t x, uint32_t y)
 | |
| {
 | |
|     int32_t posMax, negMin;
 | |
|     uint32_t i;
 | |
| 
 | |
|     posMax = 1;
 | |
| 
 | |
|     for (i = 0; i < (y - 1); i++)
 | |
|     {
 | |
|         posMax = posMax * 2;
 | |
|     }
 | |
| 
 | |
|     if (x > 0)
 | |
|     {
 | |
|         posMax = (posMax - 1);
 | |
| 
 | |
|         if (x > posMax)
 | |
|         {
 | |
|             x = posMax;
 | |
|         }
 | |
| 
 | |
| //    x &= (posMax * 2 + 1);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         negMin = -posMax;
 | |
| 
 | |
|         if (x < negMin)
 | |
|         {
 | |
|             x = negMin;
 | |
|         }
 | |
| 
 | |
| //    x &= (posMax * 2 - 1);
 | |
|     }
 | |
| 
 | |
|     return (x);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Unsigned Saturate
 | |
|   \details Saturates an unsigned value.
 | |
|   \param [in]  value  Value to be saturated
 | |
|   \param [in]    sat  Bit position to saturate to (0..31)
 | |
|   \return             Saturated value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __USAT(uint32_t value, uint32_t sat)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
|     if ((((0xFFFFFFFF >> sat) << sat) & value) != 0)
 | |
|     {
 | |
|         result = 0xFFFFFFFF >> (32 - sat);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         result = value;
 | |
|     }
 | |
| 
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Unsigned Saturate for internal use
 | |
|   \details Saturates an unsigned value, should not call directly.
 | |
|   \param [in]  value  Value to be saturated
 | |
|   \param [in]    sat  Bit position to saturate to (0..31)
 | |
|   \return             Saturated value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __IUSAT(uint32_t value, uint32_t sat)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
|     if (value & 0x80000000)   /* only overflow set bit-31 */
 | |
|     {
 | |
|         result = 0;
 | |
|     }
 | |
|     else if ((((0xFFFFFFFF >> sat) << sat) & value) != 0)
 | |
|     {
 | |
|         result = 0xFFFFFFFF >> (32 - sat);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         result = value;
 | |
|     }
 | |
| 
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   Rotate Right with Extend
 | |
|   \details This function moves each bit of a bitstring right by one bit.
 | |
|            The carry input is shifted in at the left end of the bitstring.
 | |
|   \note    carry input will always 0.
 | |
|   \param [in]    op1  Value to rotate
 | |
|   \return               Rotated value
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __RRX(uint32_t op1)
 | |
| {
 | |
| #if (__CK80X >= 2)
 | |
|     uint32_t res = 0;
 | |
|     __ASM volatile("bgeni    t0, 31\n\t"
 | |
|                    "lsri     %0, 1\n\t"
 | |
|                    "movt     %1, t0\n\t"
 | |
|                    "or       %1, %1, %0\n\t"
 | |
|                    : "=r"(op1), "=r"(res): "0"(op1), "1"(res): "t0");
 | |
|     return res;
 | |
| #else
 | |
|     uint32_t res = 0;
 | |
|     __ASM volatile("movi     r7, 0\n\t"
 | |
|                    "bseti    r7, 31\n\t"
 | |
|                    "lsri     %0, 1\n\t"
 | |
|                    "bf       1f\n\t"
 | |
|                    "mov     %1, r7\n\t"
 | |
|                    "1:\n\t"
 | |
|                    "or       %1, %1, %0\n\t"
 | |
|                    : "=r"(op1), "=r"(res): "0"(op1), "1"(res): "r7");
 | |
|     return res;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /**
 | |
|   \brief   LDRT Unprivileged (8 bit)
 | |
|   \details Executes a Unprivileged LDRT instruction for 8 bit value.
 | |
|   \param [in]    addr  Pointer to location
 | |
|   \return             value of type uint8_t at (*ptr)
 | |
|  */
 | |
| __ALWAYS_INLINE uint8_t __LDRBT(volatile uint8_t *addr)
 | |
| {
 | |
|     uint32_t result;
 | |
| //#warning "__LDRBT"
 | |
|     __ASM volatile("ldb %0, (%1, 0)" : "=r"(result) : "r"(addr));
 | |
|     return ((uint8_t) result);    /* Add explicit type cast here */
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   LDRT Unprivileged (16 bit)
 | |
|   \details Executes a Unprivileged LDRT instruction for 16 bit values.
 | |
|   \param [in]    addr  Pointer to location
 | |
|   \return        value of type uint16_t at (*ptr)
 | |
|  */
 | |
| __ALWAYS_INLINE uint16_t __LDRHT(volatile uint16_t *addr)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
| //#warning "__LDRHT"
 | |
|     __ASM volatile("ldh %0, (%1, 0)" : "=r"(result) : "r"(addr));
 | |
|     return ((uint16_t) result);    /* Add explicit type cast here */
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   LDRT Unprivileged (32 bit)
 | |
|   \details Executes a Unprivileged LDRT instruction for 32 bit values.
 | |
|   \param [in]    addr  Pointer to location
 | |
|   \return        value of type uint32_t at (*ptr)
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __LDRT(volatile uint32_t *addr)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
| //#warning "__LDRT"
 | |
|     __ASM volatile("ldw %0, (%1, 0)" : "=r"(result) : "r"(addr));
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   STRT Unprivileged (8 bit)
 | |
|   \details Executes a Unprivileged STRT instruction for 8 bit values.
 | |
|   \param [in]  value  Value to store
 | |
|   \param [in]    addr  Pointer to location
 | |
|  */
 | |
| __ALWAYS_INLINE void __STRBT(uint8_t value, volatile uint8_t *addr)
 | |
| {
 | |
| //#warning "__STRBT"
 | |
|     __ASM volatile("stb %1, (%0, 0)" :: "r"(addr), "r"((uint32_t)value) : "memory");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   STRT Unprivileged (16 bit)
 | |
|   \details Executes a Unprivileged STRT instruction for 16 bit values.
 | |
|   \param [in]  value  Value to store
 | |
|   \param [in]    addr  Pointer to location
 | |
|  */
 | |
| __ALWAYS_INLINE void __STRHT(uint16_t value, volatile uint16_t *addr)
 | |
| {
 | |
| //#warning "__STRHT"
 | |
|     __ASM volatile("sth %1, (%0, 0)" :: "r"(addr), "r"((uint32_t)value) : "memory");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   \brief   STRT Unprivileged (32 bit)
 | |
|   \details Executes a Unprivileged STRT instruction for 32 bit values.
 | |
|   \param [in]  value  Value to store
 | |
|   \param [in]    addr  Pointer to location
 | |
|  */
 | |
| __ALWAYS_INLINE void __STRT(uint32_t value, volatile uint32_t *addr)
 | |
| {
 | |
| //#warning "__STRT"
 | |
|     __ASM volatile("stw %1, (%0, 0)" :: "r"(addr), "r"(value) : "memory");
 | |
| }
 | |
| 
 | |
| /*@}*/ /* end of group CSI_Core_InstructionInterface */
 | |
| 
 | |
| 
 | |
| /* ##########################  FPU functions  #################################### */
 | |
| 
 | |
| /**
 | |
|   \brief   get FPU type
 | |
|   \details returns the FPU type, always 0.
 | |
|   \returns
 | |
|    - \b  0: No FPU
 | |
|    - \b  1: Single precision FPU
 | |
|    - \b  2: Double + Single precision FPU
 | |
|  */
 | |
| __ALWAYS_INLINE uint32_t __get_FPUType(void)
 | |
| {
 | |
|     uint32_t result;
 | |
| 
 | |
|     __ASM volatile("mfcr %0, cr<13, 0>" : "=r"(result));
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif /* _CSI_INSTR_H_ */
 |