KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记4——Directives

  • 一、若干重要的DIRECTIVE介绍
  • 二、一些概念
  • 三、Directives详细介绍
    • 1,GET/INCLUDE 文件包含
    • 2, IF...ELSE...ENDIF 条件汇编
    • 3, WHILE…ENDW 循环汇编
    • 4, DEF 符号/变量定义检查
    • 5,GBLA,GBLL,GBLS变量定义
    • 6,SETA,SETL,SETS变量赋值
    • 7,EQU符号常量赋值
    • 8,RLIST寄存器列表定义
    • 9,RN寄存器别名
    • 10,MACRO…MEND
    • 11,ROL、ROR、MOD等运算符
    • 12,EXPORT、IMPORT、EXTERN
  • 四、一些体会
  • 五、参考文件

一、若干重要的DIRECTIVE介绍

在前面的工程中,我感觉下面的这些Directives是非常有用的。

名称 功能
GET/INCLUDE 包含其他文件
IF…ELSE…ENDIF 类似与条件编译
WHILE…ENDW 重复生成代码、汇编器变量计算
DEF 类似于C中的#ifdef
GBLA,GBLL,GBLS 定义汇编器变量
SETA,SETL,SETS 汇编器变量赋值
EQU 符号赋值
RLIST 寄存器列表定义
RN 寄存器别名
MACRO…MEND 宏定义
ROL、ROR、MOD等运算符 实现汇编器运算
EXPORT、IMPORT、EXTERN 输出/引入符号

这里所有的Directives都在《ARM Developer Suite Assembler Guide》可以查到。

这些Directives是在汇编器的第一遍pass的时候被执行的。有点类似C语言的宏。

二、一些概念

三、Directives详细介绍

1,GET/INCLUDE 文件包含

这个就跟C语言下面的include是几乎一样的。可以将其他的可汇编文件内容拷贝到当前的文件里。

GET filename

这里注意GET的文件要可汇编的。所以如果弄个.h文件是不能用的。一般来说,后面的文件都是.s的。比如。

     get registers.sget irqn_vector.sget bus_clocks.s

2, IF…ELSE…ENDIF 条件汇编

具体的语法是

IF logical-expression … {ELSE …} ENDIF

注意IF、ELSE和ENDIF都不能顶格写。会被误判成符号。

可以实现条件编辑。比如我这里有一段这样写。就可以实现在设置不同的USART时钟选择的时候,给USART_BSS_VAL这个符号赋不同的值。

if USART_CLOCK_BUSEN = RCC_APB2ENR
USART_BSS_VAL   equ  (FREQ_APB2 / BAUDRATE / 16 :rol: 4) + ( FREQ_APB2 / BAUDRATE :mod: 16 )else
USART_BSS_VAL   equ  (FREQ_APB1 / BAUDRATE / 16 :rol: 4) + (FREQ_APB1 / BAUDRATE :mod: 16 )        endif

3, WHILE…ENDW 循环汇编

可以重复开始一段指令序列或directives。

WHILE logical-expression
code
WEND
where: logical-expression is an expression that can evaluate to either {TRUE} or {FALSE}

注意WHILE和ENDW都不能顶个,会被误判成符号。

我用这个指令可以实现一些数值的计算。

gbla nCal_PPRE2_Divgbla  nCal_PPRE2_Reg
nCal_PPRE2_Div                          seta    FDIV_APB2 :ror: 1
nCal_PPRE2_Reg                          seta    0while                  nCal_PPRE2_Div != 0x01
nCal_PPRE2_Reg                          seta    nCal_PPRE2_Reg + 1
nCal_PPRE2_Div                          seta    nCal_PPRE2_Div :ror: 1wend
nCal_PPRE2_Reg                          seta    nCal_PPRE2_Reg + 0x04

4, DEF 符号/变量定义检查

可以检查某个符号/变量是否在系统中被定义。

DEF :DEF:A {TRUE} if A is defined, otherwise {FALSE}.

用的时候要注意那两个冒号不能漏了。

这个运算符可以配合条件汇编、符号/变量定义实现C头文件中的那种Guard。例如下面这样的编码。先判断是否定义了_REGISTER_S_这个符号/变量。如果没有定义,就用gbll定义一个这样的汇编器变量。

 if :def: _REGISTER_S_else   gbll    _REGISTER_S_
; General Purpose Registers
callee_regs                         rlist   {r4-r12,lr};SCB
SCB_BaseAddr                        equ     0xE000ED00
SCB_CPUID                           equ     0xE000ED00
SCB_VTOR                            equ     0xE000ED08endifend

5,GBLA,GBLL,GBLS变量定义

用于定义变量。必须不能顶格写。

Directive 功能
GBLA 定义一个文内数值变量,初始值为0
GBLL 定义一个文内逻辑变量, 初始值为FALSE
GBLS 定义一个文内字符串, 初始值为null

语法为

gblx variable
where:
gblx is one of GBLA, GBLL, or GBLS.
variable is the name of the variable. variable must be unique amongst symbols within a source file.

用法在前面有出现

6,SETA,SETL,SETS变量赋值

用于给GBLx定义的变量进行赋值。必须顶格写。

Directive 功能
SETA 给一个文内数值变量赋值
SETL 给一个文内逻辑变量赋值
SETS 给一个文内字符串赋值

用法在前面已经出现过。

7,EQU符号常量赋值

给常量赋值。语法比较简单。必须顶格写。 一般来说就是:

name EQU expr{, type}

一般后面花括号里面的我不怎么用。详细的查手册吧。

这里说明一点。由于这些Directives都是运行在第一pass的,而指令都是在第二pass的时候被扫描的。所以对于指令里用的立即数,不论是汇编常量还是汇编变量,用法都是一样的。

8,RLIST寄存器列表定义

给一个通用寄存器的集合命名。必须顶格写。 语法是

name RLIST {list-of-registers}

目前我只是用来给函数需要保护的寄存器做个集合,这样在进入函数和离开函数的时候能有个统一一点的写法。

; General Purpose Registers
callee_regs                         rlist   {r4-r12,lr}

在函数里就比较方便。例如下面的这个函数。

         area USB_UART_CODE_SECTION, codealign 4
init        procpush    callee_regs...pop       callee_regsbx       lrendp

9,RN寄存器别名

给寄存器起别名。必须顶格写。 语法是

name RN expr

 ; Define the registers commonly used in this file.
rRCC            rn      r12
rGPIO           rn      r11
rUART           rn      r10
rNVIC           rn      r9
rpBuf           rn      r8
rBuf_Size       rn      r7

如果寄存器够用的话,给寄存器起别名可以大大增加汇编代码的可读性。如果不够用的话,就得好好规划一下。但是也不是说就没有机会。

具体应用如下面这段代码。

ldr  r0, [rGPIO, #GPIO_MODER]orr     r0, #TX_PIN_MODER_VAL :or: RX_PIN_MODER_VALstr  r0, [rGPIO, #GPIO_MODER]ldr     r0, [rGPIO, #GPIO_PORT_AFIO]orr     r0, #RX_PIN_AFIO_VAL:OR:TX_PIN_AFIO_VALstr      r0, [rGPIO, #GPIO_PORT_AFIO]

在每个汇编文件中,一个别名只能给一个寄存器,但是反过来不一定。就是说一个寄存器可以有多个别名。

10,MACRO…MEND

可以定义一个类似于C的内联函数或宏函数那样的存在。我叫它是汇编宏。语法是这里打不出来,直接去7-27看就好。

应用如下面这段代码。我定义了一个汇编宏叫wait_for_sr_tc_macro_via_r1 。之后只要在这个文件中需要轮询查sr_tc,就可以用这个宏。

         macro
$label      wait_for_sr_tc_macro_via_r1
$label.test_sr_tc_mldr      r1, [rUART, #USART_SR]tst       r1, #USART_SR_TCbeq     $label.test_sr_tc_m         mendalign   4
send_ch     procpush    callee_regsload_rUARTldr        r2, [rUART, #USART_CR1]orr      r2, #USART_CR1_TEstr    r2, [rUART, #USART_CR1]
before_send     wait_for_sr_tc_macro_via_r1 ;   It is important to wait for the tc to be set.;  By checking this bit via DEBUG window is not possible;  to find if this bit is set or cleared.str       r0, [rUART, #USART_DR]
after_sent      wait_for_sr_tc_macro_via_r1 ;   This is the same as the previous waiting.bic        r2, #USART_CR1_TEstr    r2, [rUART, #USART_CR1]             pop     callee_regsbx       lrendp

如果宏内需要用到跳转,可以用$label指代调用这个宏的那句的标号。

11,ROL、ROR、MOD等运算符

常用的汇编器可以直接使用的运算指令。具体语法参考手册。这里就是强调2点

  1. IMPORTEXTERN进来的符号只能用+和-进行处理,其它的运算符不支持。
  2. 汇编器的这些运算符的运算顺序和C语言是不同的。所以尽可能使用小括号约束。
  3. 不要忘了运算符单词两边的冒号。

A1466W: Operator precedence means that expression would evaluate differently in C

以上的这个警告就是提示,如果运算太长并过于复杂,建议用小括号进行限制一下。

12,EXPORT、IMPORT、EXTERN

将本文中的符号引出或引入。这个用的很常见。只是要注意,在外部weak定义的符号,如果你想覆盖它,必须把你在文件中定义的符号用export引出去才能真的覆盖。否则这个符号只是在本文中有效。

四、一些体会

灵活使用Directives,可以实现软件的可配置性,并且可以将很多原来由MCU完成的动作提前在上位机上做好。
本文中做的Keil工程可以从这个链接下载:STDIO-App的Keil工程。

五、参考文件

  1. 《ARM Developer Suite Assembler Guide》

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记4——Directives相关推荐

  1. KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记3——串口Stdio实现

    KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记3--串口Stdio实现 一.介绍 任务目标 二.工程创建 三.软件设计 第一步,BSP构建 1, 添加前面的pll_config文件 2 ...

  2. arm汇编的学习笔记,对比x86和arm(1)-从最简单的函数谈起

    最简单的函数 x86下汇编指令 ARM下汇编指令 Hello World x86中汇编指令 ARM汇编 LDM/STM指令 LDMFD 指令 ADR指令: 知识点扩展: ADR ADRL: LDR指令 ...

  3. ARM汇编指令学习笔记(一)

    (一)数据常量定义汇编指令EQU EQU用于为程序中的常量.标号等定义一个有效的字符名称,类似于C语言中的#define,当表达式为32位常量时,可指定表达式的数据类型,CODE16,CODE32,D ...

  4. arm cef3 linux 编译_【学习笔记】CEF Linux编译

    源码编译部分转载:https://bitbucket.org/chromiumembedded/cef/wiki/MasterBuildQuickStart#markdown-header-linux ...

  5. keil 生成bin找不到afx文件_【学习笔记】Keil不能正确生成.bin文件的解决办法

    前段时间我写过如何利用CW.IAR和Keil生成image文件,效果还不错,有些用户反馈挺有帮助的,毕竟待项目开发到最后是需要生成image文件用来量产烧写,我们总不至于到最后使用调试下载吧(不过还别 ...

  6. Arm技术文档全集合(含AMBA总线,Cortex-A,Contex-M,Cortex-R系列处理器,Arm体系结构,Arm服务器,Mali GPU,Keil 开发等PDF下载)

    在这里可以下载到所有Arm技术方面的文档,我们已经为大家归类好资料,方便大家学习!持续更新中,大家可点击右下角的收藏图标收藏本帖,如果大家有补充,欢迎评论~ 首发极术社区 Cortex-A系列处理器 ...

  7. [ARM] [基础][编译]ARM的浮点功能历史分类和对应的编译选项

    前言:ARM编译的时候有很多编译选项和浮点功能相关,要真正理解这些编译选项的选择,不仅仅要了解ARM的体系构建的基础知识,可能还需要了解一下ARM的历史.之后,真对这些再考虑到ARM编译选项就比较好理 ...

  8. NXP i.MX 8M Plus工业开发板硬件说明书( 四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

    前  言 本文主要介绍创龙科技TLIMX8MP-EVM评估板硬件接口资源以及设计注意事项等内容. 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex- ...

  9. NXP i.MX 8M Plus工业开发板硬件说明书--上册( 四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

    前  言 本文档主要介绍创龙科技TLIMX8MP-EVM评估板硬件接口资源以及设计注意事项等内容. 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex ...

最新文章

  1. Python 为什么要保留显式的 self ?
  2. DrugVQA | 用视觉问答技术预测药物蛋白质相互作用
  3. 用户自定义的标识符的一些注意事项
  4. 选择存储服务器硬盘并解决一些疑问
  5. java 爬中 验证码识别_JAVA爬虫---验证码识别技术(一)
  6. oracle有 哪些常用视图,oracle常用视图
  7. ITK:重新运行管道不断变化的最大可能的地区
  8. 一起谈.NET技术,Visual Studio与C#编程十个实用技巧
  9. hdu-6165(tarjan+topusort)
  10. 价值投资/指标选股(akshare)
  11. security工作笔记006---oauth2(spring security)报错method_not_allowed(Request method 'GET' not supported)解决
  12. 3 | Spatial-based GNN/convolution模型之 NN4G
  13. 修改ASM磁盘组冗余模式(一):copy-switch方式
  14. java函数式编程例子_java函数式编程Lambda表达式的示例(一)
  15. 什么是BI(Business Intelligence
  16. 如何创建从硬盘安装的硬像文件
  17. 现实世界与虚拟世界的差别在哪里
  18. 菜鸟教程Python100例-笔记
  19. python,matlab 读取NIFTI(.nii)格式图像、FSL安装
  20. python中sys是什么意思_python里的sys是什么意思

热门文章

  1. 带有Docker的容器
  2. 关于DNS负载均衡技术
  3. MFC 修改AfxMessageBox默认标题
  4. 见证奇瑞新QQ 1.0MT十年间的蜕变
  5. 使用python给女朋友自动发晚安
  6. 联通、电信、移动的3G、4G速度与进度
  7. [vscode] 代码提示不能默认选中第一项问题
  8. C# 多个TcpClient 的区分处理
  9. CDH6.3.2 Hive安装
  10. 用牛顿迭代法非线性方程的实根