/********************************************************************* * (c) SEGGER Microcontroller GmbH * * The Embedded Experts * * www.segger.com * ********************************************************************** -------------------------- END-OF-HEADER ----------------------------- File : SEGGER_RTT_ASM_ARMv7M.S Purpose : Assembler implementation of RTT functions for ARMv7M Additional information: This module is written to be assembler-independent and works with GCC and clang (Embedded Studio) and IAR. */ #define SEGGER_RTT_ASM // Used to control processed input from header file #include "SEGGER_RTT.h" /********************************************************************* * * Defines, fixed * ********************************************************************** */ #define _CCIAR 0 #define _CCCLANG 1 #if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__) #define _CC_TYPE _CCCLANG #define _PUB_SYM .global #define _EXT_SYM .extern #define _END .end #define _WEAK .weak #define _THUMB_FUNC .thumb_func #define _THUMB_CODE .code 16 #define _WORD .word #define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax" #define _ALIGN(Exp) .align Exp #define _PLACE_LITS .ltorg #define _DATA_SECT_START #define _C_STARTUP _start #define _STACK_END __stack_end__ #define _RAMFUNC // // .text => Link to flash // .fast => Link to RAM // OtherSect => Usually link to RAM // Alignment is 2^x // #elif defined (__IASMARM__) #define _CC_TYPE _CCIAR #define _PUB_SYM PUBLIC #define _EXT_SYM EXTERN #define _END END #define _WEAK _WEAK #define _THUMB_FUNC #define _THUMB_CODE THUMB #define _WORD DCD #define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp) #define _ALIGN(Exp) alignrom Exp #define _PLACE_LITS #define _DATA_SECT_START DATA #define _C_STARTUP __iar_program_start #define _STACK_END sfe(CSTACK) #define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR // // .text => Link to flash // .textrw => Link to RAM // OtherSect => Usually link to RAM // NOROOT => Allows linker to throw away the function, if not referenced // Alignment is 2^x // #endif #if (_CC_TYPE == _CCIAR) NAME SEGGER_RTT_ASM_ARMv7M #else .syntax unified #endif #if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) #define SHT_PROGBITS 0x1 /********************************************************************* * * Public / external symbols * ********************************************************************** */ _EXT_SYM __aeabi_memcpy _EXT_SYM __aeabi_memcpy4 _EXT_SYM _SEGGER_RTT _PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock /********************************************************************* * * SEGGER_RTT_WriteSkipNoLock * * Function description * Stores a specified number of characters in SEGGER RTT * control block which is then read by the host. * SEGGER_RTT_WriteSkipNoLock does not lock the application and * skips all data, if the data does not fit into the buffer. * * Parameters * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. * NumBytes Number of bytes to be stored in the SEGGER RTT control block. * MUST be > 0!!! * This is done for performance reasons, so no initial check has do be done. * * Return value * 1: Data has been copied * 0: No space, data has not been copied * * Notes * (1) If there is not enough space in the "Up"-buffer, all data is dropped. * (2) For performance reasons this function does not call Init() * and may only be called after RTT has been initialized. * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. */ _SECTION(.text, CODE, 2) _ALIGN(2) _THUMB_FUNC SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) { // // Cases: // 1) RdOff <= WrOff => Space until wrap-around is sufficient // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) // 3) RdOff < WrOff => No space in buf // 4) RdOff > WrOff => Space is sufficient // 5) RdOff > WrOff => No space in buf // // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough // // Register usage: // R0 Temporary needed as RdOff, register later on // R1 pData // R2 // R3 register. Hold free for subroutine calls // R4 // R5 pRing->pBuffer // R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN) // R7 WrOff // PUSH {R4-R7} ADD R3,R0,R0, LSL #+1 LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex]; ADD R0,R0,R3, LSL #+3 ADD R6,R0,#+24 LDR R0,[R6, #+16] // RdOff = pRing->RdOff; LDR R7,[R6, #+12] // WrOff = pRing->WrOff; LDR R5,[R6, #+4] // pRing->pBuffer CMP R7,R0 BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3) // // Handling for case 1, later on identical to case 4 // LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) SUBS R4,R3,R7 // (Used in case we jump into case 2 afterwards) SUBS R3,R4,#+1 // CMP R3,R2 BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)? _Case4: ADDS R5,R7,R5 // pBuffer += WrOff ADDS R0,R2,R7 // v = WrOff + NumBytes // // 2x unrolling for the copy loop that is used most of the time // This is a special optimization for small SystemView packets and makes them even faster // _ALIGN(2) _LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes); LDRB R3,[R1], #+1 STRB R3,[R5], #+1 // *pDest++ = *pSrc++ SUBS R2,R2,#+1 BEQ _CSDone LDRB R3,[R1], #+1 STRB R3,[R5], #+1 // *pDest++ = *pSrc++ SUBS R2,R2,#+1 BNE _LoopCopyStraight _CSDone: #if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct #endif STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes; MOVS R0,#+1 POP {R4-R7} BX LR // Return 1 _CheckCase2: ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around CMP R0,R2 BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit) // // Handling for case 2 // ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer) _LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk LDRB R3,[R1], #+1 STRB R3,[R0], #+1 // *pDest++ = *pSrc++ SUBS R4,R4,#+1 BNE _LoopCopyBeforeWrapAround // // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks // Therefore, check if 2nd memcpy is necessary at all // ADDS R4,R2,#+0 // Save (needed as counter in loop but must be written to after the loop). Also use this inst to update the flags to skip 2nd loop if possible BEQ.N _No2ChunkNeeded // if (NumBytes) { _LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes); LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop STRB R3,[R5], #+1 // *pDest++ = *pSrc++ SUBS R2,R2,#+1 BNE _LoopCopyAfterWrapAround _No2ChunkNeeded: #if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct #endif STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer MOVS R0,#+1 POP {R4-R7} BX LR // Return 1 _CheckCase4: SUBS R0,R0,R7 SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u; CMP R0,R2 BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit) _Case3: MOVS R0,#+0 POP {R4-R7} BX LR // Return 0 _PLACE_LITS #endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) _END /*************************** End of file ****************************/