分享

单片机C代码嵌套汇编常见写法

 zmc419 2023-10-20 发布于河南

有代码运行的机器,就有汇编代码的身影,不管是PC,还是手机、平板,最底层都离开汇编代码。

前面给大家分享过单片机用汇编和C语言点灯程序的区别,今天给大家分享一下单片机C代码嵌套汇编常见写法。

嵌套汇编与编译器有关

有认真研究,或者说细心一点的读者应该都知道:C中定义汇编代码与编译器有关

比如:你在core_cm4.h文件会看到如下的代码:
#if defined ( __CC_ARM ) #define __ASM __asm /*!< asm keyword for ARM Compiler */ #define __INLINE __inline /*!< inline keyword for ARM Compiler */ #define __STATIC_INLINE static __inline
#elif defined ( __GNUC__ ) #define __ASM __asm /*!< asm keyword for GNU Compiler */ #define __INLINE inline /*!< inline keyword for GNU Compiler */ #define __STATIC_INLINE static inline
#elif defined ( __ICCARM__ ) #define __ASM __asm /*!< asm keyword for IAR Compiler */ #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ #define __STATIC_INLINE static inline
#elif defined ( __TMS470__ ) #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ #define __STATIC_INLINE static inline
#elif defined ( __TASKING__ ) #define __ASM __asm /*!< asm keyword for TASKING Compiler */ #define __INLINE inline /*!< inline keyword for TASKING Compiler */ #define __STATIC_INLINE static inline
#elif defined ( __CSMC__ ) #define __packed #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ #define __INLINE inline /*use -pc99 on compile line !< inline keyword for COSMIC Compiler */  #define __STATIC_INLINE  static inline#endif

图片

如果你写过Keil C51,你还会发现有如下(通过预处理)嵌套汇编:
#pragma asm
; Assembler Code Here
#pragma endasm

所以,你会发现,不同的编译器,汇编代码还是有差异。当然,这里主要是说C中嵌套汇编与编译器有关

C中嵌套汇编代码

常见两种定义:
1.在C函数中定义一段汇编代码;
2.在C文件中定义一个汇编函数;
(当然,两个意思差不多,都是在C中嵌套汇编)

上面说了C中定义汇编代码与编译器有关,换句话说:不同编译器解析汇编代码的方式不同。

这里还是拿core_cm3.c来举例说明,定义一个__get_PSP函数。

在Keil MDK中定义:
__ASM uint32_t __get_PSP(void){ mrs r0, psp bx lr}

在IAR EWARM中定义:
uint32_t __get_PSP(void){ __ASM('mrs r0, psp'); __ASM('bx lr');}

__asm(__ASM)关键字用于调用内联汇编程序,并且可在 C 或 C++ 语句合法时出现。

更多案例

下面分享一些在单片机中常见的例子。

1.FreeRTOS中portmacro.h文件下源代码:
static portFORCE_INLINE void vPortRaiseBASEPRI( void ){uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm { /* Set BASEPRI to the max syscall priority to effect a critical section. */ msr basepri, ulNewBASEPRI dsb isb }}

2.FreeRTOS中port.c文件下源代码:
__asm void xPortPendSVHandler( void ){ extern uxCriticalNesting; extern pxCurrentTCB; extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp isb
ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */ ldr r2, [r3]
stmdb r0!, {r4-r11} /* Save the remaining registers. */ str r0, [r2] /* Save the new top of stack into the first member of the TCB. */
stmdb sp!, {r3, r14} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 dsb isb bl vTaskSwitchContext mov r0, #0 msr basepri, r0 ldmia sp!, {r3, r14}
ldr r1, [r3] ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */ msr psp, r0 isb bx r14 nop}

3.内核复位
这是之前分享过的一篇文章《STM32复位来源》中的代码:
__asm void NVIC_CoreReset_a(void){ LDR R0, =0xE000ED0C LDR R1, =0x05FA0001 STR R1, [R0]deadloop_Core B deadloop_Core}

举了这些常见例子,相信大家只要认真理解都能明白。

------------ END ------------


●专栏《嵌入式工具

●专栏《嵌入式开发》

●专栏《Keil教程》

●嵌入式专栏精选教程

关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多