《ARM Cortex-M3与Cortex-M4权威指南》 第5章 指令集

5.1 ARM Cortex - M处理器指令集的背景简介

ARM Cortex - M处理器指令集是基于ARMv7 - M架构设计的,旨在为嵌入式系统提供高效、紧凑的指令集合。它结合了16位Thumb指令和32位Thumb - 2指令的优势,以满足不同应用场景对代码密度和性能的需求。16位Thumb指令有助于提高代码密度,减少存储需求,而32位Thumb - 2指令则增强了指令的表达能力和执行效率,使得处理器在处理复杂任务时更加得心应手。这种指令集设计模式,通过灵活组合不同长度的指令,优化了嵌入式系统在资源受限情况下的性能表现。

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

不同型号的ARM Cortex - M处理器指令集存在一定差异。例如,Cortex - M0和Cortex - M0 + 指令集相对精简,主要侧重于低成本和低功耗应用,支持基本的算术、逻辑和数据传输指令。而Cortex - M3和Cortex - M4在此基础上进行了扩展,增加了更多功能指令,如Cortex - M4引入了针对数字信号处理(DSP)和浮点运算的指令集。这种设计模式使得ARM能够针对不同的市场需求,提供具有差异化功能的处理器,开发者可根据应用的具体需求选择合适的处理器型号及其指令集。

5.3 理解汇编语言语法

汇编语言是一种面向机器的编程语言,与处理器的指令集紧密相关。在ARM汇编语言中,每条指令由操作码(如 ADD 表示加法操作)和操作数(如寄存器或立即数)组成。例如,ADD R0, R1, R2 表示将寄存器 R1 和 R2 的值相加,结果存储在寄存器 R0 中。注释使用 ; 开始,用于对代码进行解释说明,提高代码的可读性。汇编语言的语法设计模式遵循特定的规则,使得程序员能够精确控制处理器的操作,直接访问硬件资源,但同时也要求程序员对处理器架构有深入的了解。

5.4 指令后缀的使用

指令后缀用于进一步指定指令的行为或操作数类型。例如,在数据处理指令中,S 后缀表示该指令会影响状态标志位(如 ADD S R0, R1, R2,执行加法操作并更新状态标志位)。在存储器访问指令中,后缀可以表示数据的大小,如 LDRB 表示加载字节数据(LDR 是加载字数据),STRH 表示存储半字数据(STR 是存储字数据)。这种通过后缀来细化指令功能的设计模式,增加了指令集的灵活性,使程序员能够根据具体需求选择合适的指令变体。

5.5 统一汇编语言(UAL)

统一汇编语言(UAL)是一种尝试为不同ARM架构提供统一汇编语法的方法。它允许程序员使用一种通用的语法编写汇编代码,而不必过多关注具体的ARM架构细节。例如,在UAL中,某些指令的写法可以在不同的ARM处理器上保持一致,这有助于提高代码的可移植性。然而,实际应用中,不同的ARM处理器可能仍需要根据其特定的架构进行微调。UAL的设计模式旨在简化跨平台汇编编程,减少程序员在不同架构间移植代码的工作量。

5.6 指令集

5.6.1 处理器内传送数据

MOV指令:用于在寄存器之间传送数据或将立即数传送到寄存器。例如,MOV R0, R1 将寄存器 R1 的值传送到寄存器 R0;MOV R0, #10 将立即数10传送到寄存器 R0。这种指令实现了数据在处理器内部寄存器之间的快速传递,类似于一种数据搬运的设计模式,为后续的运算操作准备数据。MVN指令:将操作数按位取反后传送到目标寄存器。例如,MVN R0, R1 将寄存器 R1 的值按位取反后传送到寄存器 R0。常用于需要对数据进行逻辑取反操作的场景。

5.6.2 存储器访问指令

LDR指令:从存储器中加载数据到寄存器。例如,LDR R0, [R1] 从寄存器 R1 指向的内存地址中加载一个字(32位)数据到寄存器 R0。这里体现了一种从存储设备到处理器寄存器的数据读取模式,满足了处理器对外部数据的获取需求。STR指令:将寄存器中的数据存储到存储器中。例如,STR R0, [R1] 将寄存器 R0 的值存储到寄存器 R1 指向的内存地址中。这与 LDR 指令相反,实现了从处理器寄存器到存储设备的数据写入模式。

5.6.3 算术运算

ADD指令:执行加法运算。例如,ADD R0, R1, R2 将寄存器 R1 和 R2 的值相加,结果存储在寄存器 R0 中。加法运算是基本的算术运算之一,广泛应用于各种数值计算场景,体现了基本算术运算的设计模式。SUB指令:执行减法运算。例如,SUB R0, R1, R2 从寄存器 R1 的值中减去寄存器 R2 的值,结果存储在寄存器 R0 中。用于实现数值的减法操作,与加法运算共同构成了基本的算术运算体系。

5.6.4 逻辑运算

AND指令:执行按位与运算。例如,AND R0, R1, R2 将寄存器 R1 和 R2 的值按位进行与操作,结果存储在寄存器 R0 中。常用于屏蔽某些位或提取特定位的操作,是逻辑运算中的一种基本操作模式。ORR指令:执行按位或运算。例如,ORR R0, R1, R2 将寄存器 R1 和 R2 的值按位进行或操作,结果存储在寄存器 R0 中。用于合并某些位或设置特定位的操作。

5.6.5 移位和循环移位指令

LSL指令:逻辑左移指令。例如,LSL R0, R1, #2 将寄存器 R1 的值逻辑左移2位,结果存储在寄存器 R0 中。左移操作可以实现对数值的快速乘法运算(乘以2的幂次方),体现了通过移位操作实现特定数学运算的设计模式。ASR指令:算术右移指令。例如,ASR R0, R1, #3 将寄存器 R1 的值算术右移3位,结果存储在寄存器 R0 中。算术右移保留符号位,常用于有符号数的除法运算(除以2的幂次方)。

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

UXTB指令:无符号扩展字节指令。例如,UXTB R0, R1 将寄存器 R1 的低8位无符号扩展为32位后存储在寄存器 R0 中。用于将小数据类型扩展为大数据类型,以满足不同运算对数据位宽的要求。REV指令:反转字节顺序指令。例如,REV R0, R1 将寄存器 R1 中的4个字节顺序反转后存储在寄存器 R0 中。常用于处理不同字节序的数据。

5.6.7 位域处理指令

BFXIL指令:位域提取并插入指令。例如,BFXIL R0, R1, #4, #3 从寄存器 R1 中提取从第4位开始长度为3位的位域,然后插入到寄存器 R0 的相同位置。用于对寄存器中的位域进行灵活的提取和插入操作,在处理复杂数据结构或协议解析时经常用到。

5.6.8 比较和测试

CMP指令:比较指令。例如,CMP R0, R1 将寄存器 R0 和 R1 的值进行比较,根据比较结果设置状态标志位(如 N、Z、C、V)。常用于条件判断,决定程序的分支走向,是实现条件控制流的重要指令。TST指令:测试指令。例如,TST R0, #0x01 将寄存器 R0 的值与立即数0x01按位进行与操作,并根据结果设置状态标志位,常用于测试特定位是否为1。

5.6.9 程序流控制

B指令:无条件跳转指令。例如,B label 跳转到名为 label 的地址处继续执行。用于改变程序的执行顺序,实现程序的分支和循环等结构。BL指令:带链接的跳转指令。例如,BL function 跳转到名为 function 的函数地址处执行,并将返回地址存储在链接寄存器 LR 中。用于函数调用,体现了函数调用和返回的程序控制设计模式。

5.6.10 饱和运算

QADD指令:饱和加法指令。例如,QADD R0, R1, R2 将寄存器 R1 和 R2 的值相加,结果如果超出了饱和范围(如32位有符号数的范围),则将结果设置为饱和值(最大值或最小值),并设置 Q 标志位。常用于数字信号处理中,防止运算结果溢出导致数据丢失。

5.6.11 异常相关指令

SVC指令:系统服务调用指令。例如,SVC #0x01 触发系统服务调用,操作系统可以根据传递的参数(这里是0x01)执行相应的系统服务。用于用户程序请求操作系统提供的服务,是实现用户态与系统态交互的重要机制。

5.6.12 休眠模式相关指令

WFI指令:等待中断指令。执行该指令后,处理器进入低功耗的休眠模式,直到有中断发生才唤醒。例如,在一些对功耗要求较高的应用中,当系统处于空闲状态时,可以执行 WFI 指令进入休眠模式,降低功耗,体现了通过指令控制处理器功耗的设计模式。

5.6.13 存储器屏障指令

DMB指令:数据内存屏障指令。例如,DMB 指令确保在该指令之前的所有内存访问操作都完成后,才执行后续的内存访问操作。用于保证内存访问的顺序性,在多处理器系统或涉及共享内存的场景中非常重要,防止内存访问的乱序执行导致数据不一致。

5.6.14 其他指令

NOP指令:空操作指令。执行该指令不进行任何实际操作,仅消耗一个时钟周期。常用于延迟或占位,例如在代码调试时,可能需要在特定位置插入 NOP 指令来调整代码执行时间。

5.6.15 不支持的指令

Cortex - M处理器不支持一些ARM架构中的指令,如ARM指令集模式下的某些指令,以及一些用于特定高端应用或复杂系统功能的指令。这是由于Cortex - M处理器主要面向嵌入式应用,对指令集进行了精简,去除了一些在嵌入式场景中很少使用的指令,以降低硬件复杂度和成本。

5.7 Cortex - M4特有的指令

5.7.1 Cortex - M4的增强DSP扩展简介

Cortex - M4引入了增强的数字信号处理(DSP)扩展指令集,以提高在数字信号处理领域的性能。这些指令针对DSP算法中的常见操作进行了优化,如乘法累加(MAC)运算、向量运算等,使得处理器能够更高效地处理音频、视频、电机控制等应用中的数字信号处理任务。

5.7.2 SIMD和饱和指令

SIMD(单指令多数据)指令:允许一条指令同时对多个数据元素进行操作。例如,VADD.S16 q0, q1, q2 对两个16位向量寄存器 q1 和 q2 中的数据进行加法操作,并将结果存储在向量寄存器 q0 中。这种指令模式提高了数据处理的并行性,适用于处理大量相似数据的场景,如音频信号处理中的样本数据。饱和指令:在Cortex - M4中进一步增强了饱和运算能力,如 QSUB16 指令,用于16位有符号数的饱和减法运算,确保结果在饱和范围内,防止溢出导致的数据错误。

5.7.3 乘法和MAC指令

乘法指令:如 SMULBB 指令,用于两个8位有符号数相乘,结果为16位有符号数。在数字信号处理中,经常需要进行小数乘法运算,这些指令提供了更细粒度的乘法操作。MAC(乘累加)指令:如 SMLALBB 指令,将两个8位有符号数相乘,结果累加到64位累加器中。MAC运算在数字滤波器等DSP算法中广泛应用,通过这种指令可以高效地实现这些算法。

5.7.4 打包和解包

打包指令:例如 PKHBT 指令,将两个8位数据打包成一个16位数据。在处理多个小数据元素时,通过打包操作可以将它们组合成一个更大的数据单元,便于存储和传输。解包指令:如 UXTAB16 指令,将16位数据解包为两个8位数据。与打包操作相反,用于从组合的数据单元中提取出原始的小数据元素。

5.7.5 浮点指令

Cortex - M4支持单精度浮点运算指令,如 VLDR.F32 s0, [r0] 从内存地址 r0 加载一个单精度浮点数到浮点寄存器 s0。浮点指令使得处理器能够处理更复杂的数值计算,在科学计算、图形处理等领域有重要应用。

5.8 桶形移位器

桶形移位器是ARM处理器中的一个硬件组件,它能够在一个时钟周期内对寄存器中的数据进行各种移位操作,包括逻辑移位、算术移位和循环移位。例如,在执行 LSL R0, R1, #4 指令时,桶形移位器负责将寄存器 R1 的值逻辑左移4位,并将结果传递给寄存器 R0。桶形移位器的设计模式提高了移位操作的效率,避免了通过软件循环实现移位操作的复杂性和低效率。

5.9 在编程中访问特殊寄存器和特殊指令

5.9.1 简介

特殊寄存器(如程序状态寄存器、控制寄存器等)和特殊指令(如用于异常处理、系统控制的指令)在ARM Cortex - M处理器的编程中起着关键作用。访问这些特殊寄存器和执行特殊指令需要特定的方法,以确保程序能够正确控制处理器的行为和状态。

5.9.2 内在函数

许多编译器提供内在函数来访问特殊寄存器和执行特殊指令。例如,在ARM GCC编译器中,__get_CONTROL() 函数用于获取控制寄存器 CONTROL 的值,__set_PRIMASK(1) 函数用于设置中断屏蔽寄存器 PRIMASK,屏蔽所有中断。内在函数提供了一种相对简洁且可移植的方式来访问特殊寄存器和执行特殊指令,类似于一种封装的设计模式,将对硬件寄存器的操作封装在函数中,提高了代码的可读性和可维护性。

5.9.3 内联汇编和嵌入汇编

内联汇编:允许在C语言代码中直接嵌入汇编指令。例如,在GCC编译器中,可以使用如下方式:

int main() {

int result;

__asm__ volatile (

"MOV R0, #10\n\t"

"MOV R1, #20\n\t"

"ADD R2, R0, R1\n\t"

"MOV %0, R2\n\t"

: "=r" (result)

:

: "R0", "R1", "R2"

);

return result;

}

这里通过 __asm__ 关键字嵌入汇编代码,实现了简单的加法运算,并将结果存储在C语言变量 result 中。内联汇编提供了直接访问硬件资源的能力,适用于需要对硬件进行精细控制的场景。

嵌入汇编:一些编译器还支持将汇编代码块嵌入到C语言源文件中。例如,在IAR编译器中,可以使用 #pragma inline 指令来实现嵌入汇编。这种方式在处理复杂的汇编代码逻辑时更加方便,同时也能与C语言代码更好地集成。

5.9.4 使用其他的编译器相关的特性

不同的编译器可能提供一些特定的特性来访问特殊寄存器和执行特殊指令。例如,Keil编译器提供了一些预定义的宏来访问特殊寄存器,如 __get_PSP() 用于获取进程堆栈指针。开发者需要熟悉所使用编译器的特性,以便更高效地进行编程。

5.9.5 访问特殊寄存器

除了通过内在函数和汇编方式访问特殊寄存器外,一些微控制器厂商还提供了基于寄存器映射的方式。例如,在某些基于Cortex - M的微控制器中,通过定义与特殊寄存器地址对应的结构体,来访问特殊寄存器的各个位。例如:

typedef struct {

__IO uint32_t CONTROL;

__IO uint32_t IPSR;

// 其他特殊寄存器定义

} SCB_TypeDef;


官银的由来及拖欠官银的处罚 | 法治文化
庭院花园设计软件推荐与使用指南