前言:本文章相当于学习笔记,摘录总结。推荐自行观看相关书籍(权威指南),不足之处,请指点。
5.1ARM Cortex-M处理器指令集的背景简介
Cortex-M处理器使用了Thumb-2技术,一个操作状态可以32位和16位指令混合使用。
ARM处理器是ARM和Thumb状态进行切换。ARM处理器编译时,部分应用程序编译成32位,部分编译成16位,这样可以提高代码密度。其实本质是,arm处理器有一个译码器,它会将16位的指令映射成32位,然后再执行。
Cortex-A/R处理器保留了这两种运行状态。

5.2ARM Cortex-M处理器间的指令集比较


指令向上兼容,比如Cortex-M0编译的代码,能在Cortex-M3上使用。
ARMv6-M的指令多数是16位的,但是有些指令有16位和32位两个版本。通常编译器会使用16位版本,但是如果需要更大的寄存器范围、立即数、或者地址区域、寻址模式,编译器就会使用32位版本。
5.3理解汇编语言语法
不同供应商的汇编工具,语法上可能会有区别。大多数助记符和汇编指令是相同,但汇编伪指令、定义、标号、注释语法可能会有所不同。
ARM汇编格式:

GUN工具链汇编格式:

label是可选的,表示地址位置,通过label可以得到指令地址,也可以用于表示数据地址。
mnemonic(助记符)也是指令名。
operand为操作数,根据指令不同,操作数个数不同,用法不同。
汇编定义常量:
举例:NVIC_IRQ_EN EQU 0xE000E100
LDR R0, = NVIC_IRQ_EN
允许将数据插入程序中:

DCD用于插入字大小的数据,当需要插入字大小的数据时,需要增加ALIGN伪指令,进行对齐,4代表对齐的大小。ALIGN 4 表示对齐将下面的数据对齐到字边界。
DCB用于将字节大小的数据插入到程序中。



5.4指令后缀的使用
有些指令后面可以跟着一些后缀。

举例:

5.5统一汇编语言(UAL)
一句话总结:以前的Thumb指令和现在的Thumb-2指令,在用法上有所区别。为了兼容推出了UAL,建议使用UAL来写汇编。
5.6指令集
5.6.1处理器内传送数据

5.6.2存储器访问指令


1.立即数偏移(前序)



2.PC相关寻址(文本)

3.寄存器偏移(前序)

4.后序

5.多加载和多存储



6.压栈和出栈


7.SP相关寻址

8.非特权访问等级下的加载和存储

9.排他访问

5.6.3算术运算

5.6.4逻辑运算

5.6.5移位和循环移位指令

5.6.6数据转换运算(展开和反序)


5.6.7位域处理指令

5.6.8比较和测试

5.6.9程序流控制
1.跳转

2.函数调用

3.条件跳转
条件跳转基于APSR的当前值条件执行。



4.比较和跳转
ARMv7-M架构提供了两个新的指令:
CBZ:比较为0则跳转
CBNZ:比较非0则跳转

5.条件执行(IF-THEN指令)

6.表格跳转
TBB(表格跳转字节)和TBH(表格跳转半字),主要用于实现switch
5.6.10饱和运算
有符号和无符号数据饱和调整的指令:
SSAT(用于有符号数据)

USAT(用于无符号数据)

5.6.11异常相关指令
管理调用(SVC)指令用于产生SVC异常(异常类型为11)。SVC一般用于嵌入式OS/实时OS(RTOS),其中,运行在非特权执行状态的应用可以请求运行在特权状态的OS的服务。SVC异常机制提供了从非特权到特权的转换。

immed为立即数,可以充当参数,传递给SVC异常处理函数,用来识别需要是什么服务。
改变处理器状态(CPS)指令。可以使用这条指令来设置或清除PRIMASK 和FAULTMASK等中断屏蔽寄存器。

5.6.12休眠模式相关指令
WFI指令:等待中断(进入休眠),也可以用cmsis库的_WFI()函数。
WFE指令:等待事件(条件进入休眠),也可以使用cmsis库的_WFE()函数。
处理器内部有一个一位的寄存器,该位置1,WFE指令不会进入睡眠,而是清除事件寄存器,然后执行下一条指令;如果清0,则进入睡眠,需要被事件唤醒。
在多处理器系统中,处理器1进行WFE睡眠后,处理器2可以通过SEV指令发送事件,唤醒处理器1。
5.6.13存储器屏障指令
对于ARM架构(包括ARMv7-M在内),在不影响数据处理结果的情况下,存储器传输的顺序可以和程序代码不同。这种情况对于具有超矢量或乱序执行能力的高端处理器是很常见的。不过,在对存储器访问重新排序之后,若数据在多个处理器间共用,则另一个处理器看到的数据顺序可能和设定的不同,这样可能会引起错误。


Cortex-M处理器流水线简单,且AHB Lite总线协议不允许对传输重新排序,所以一般来说可以不用,但是以下情况,建议使用:


5.6.14其他指令
NOP指令(_NOP();)用于产生指令对齐或者延时
BKPT(断点指令)用于实现应用程序中的软件断点。
5.6.15不支持的指令




5.7Cortex-M4特有的指令
5.7.1Cortex-M4的增强DSP扩展简介
相对于Cortex-M3多了DSP处理指令
5.7.2SIMD和饱和指令
就是为了加速音视频数据处理的指令
5.7.3乘法和MAC指令
作用就是加速运算
5.7.4打包和解包
作用就是为了方便SIMD数据的打包和解包
5.7.5浮点指令
用于浮点运算的指令,但需要使能SCB->CPACR,并且设备头文件的_FPU_PRESENT要置1。一般在微控制器厂商提供的SystemInit()函数中会进行这一操作。
5.8桶形移位器

作用就是你在数据处理器前,就可以通过桶形移位器进行移位,这样你本来需要先移位,再处理数据两条指令。现在只需要一条指令就能够解决,执行速度翻倍。
5.9在编程中访问特殊寄存器和特殊指令
5.9.1简介
就是有些指令,是普通C代码编译出来的。比如存储器屏障指令,要使用这些指令,只能通过其他方式。
还有如何访问一些特殊的寄存器。
5.9.2内在函数
1.CMSIS-Core内在函数
这个库的头文件里有一些函数,可以访问特殊寄存器
2.编译器相关的内在函数
编译器有一些函数可以使用,不同的编译器,函数可能不相同。
5.9.3内联汇编和嵌入汇编
可以在C代码中插入汇编代码
5.9.4使用其他的编译器相关的特性
多数编译器具有可以产生特殊指令的特性,比如ARM C编译器,可以利用_svc关键字插入SVC指令。
习语识别,比如以某种形式写的数据运算C语句,编译器可以识别出来转换成简单的指令进行替代。
5.9.5访问特殊寄存器
ARM编译器内部已经对一些寄存器进行了命名,可以通过语法直接访问对应的寄存器。
语法为:






