![嵌入式技术基础与实践(第5版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/467/31794467/b_31794467.jpg)
2.2 指令系统
CPU的功能是从外部设备获得数据,通过加工、处理,再把处理结果送到CPU的外部世界。设计一个CPU,首先需要设计一套可以执行特定功能的操作命令,这种操作命令称为指令。CPU所能执行的各种指令的集合,称为该CPU的指令系统。表2-4所示为ARM Cortex-M指令集概况。在ARM系统中,架构(Architecture)即体系结构,主要指使用的指令集,由同一架构可以衍生出许多不同处理器型号。对ARM而言,其他芯片厂商,可由ARM提供的一种处理器型号具体生产出许多不同的MCU或应用处理器型号。ARMv7-M是一种架构型号,其中v7是指版本号,而基于该架构处理器的有Cortex-M3、Cortex-M4、Cortex-M4F等。
表2-4 ARM Cortex-M指令集概况
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T57_28507.jpg?sign=1739522942-4ZglQ66C0gx6DagNfP2wLSd8WMbBJYyZ-0-be1e78d37bb5669e804a934d784a937c)
本节在给出指令简表与寻址方式的基础上,简要阐述ARM Cortex-M系列共有的57条基本指令功能。
2.2.1 指令简表与寻址方式
1. 指令简表
ARM Cortex-M4F不仅支持所有的Thumb和Thumb-2的全部指令,还支持浮点运算指令、DSP扩展指令等。常用的指令大体分为数据操作指令、转移指令、存储器数据传送指令和其他指令四大类,如表2-5所示。其他指令需要时请查阅《ARMv7-M参考手册》。
表2-5 常用指令简表
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T58_28509.jpg?sign=1739522942-zBcRHW8lEYxjEj8jZSVX4qVJtRIrQ9rO-0-d38b1ddf9231b8c914ba15e938051168)
2. 寻址方式
指令是对数据的操作,通常把指令中所要操作的数据称为操作数,ARM Cortex-M4F处理器所需的操作数可能来自寄存器、指令代码、存储单元。而确定指令中所需操作数的各种方法称为寻址方式(Addressing Mode)。下面指令格式中的“{}”表示其中可选项。例如,LDRH Rt,[Rn{,#imm}],表示有“LDRH Rt,[Rn]”“LDRH Rt,[Rn,#imm]”两种指令格式。指令中的“[]”表示其中内容为地址,“//”表示注释。
1)立即数寻址
在立即数寻址方式中,操作数直接通过指令给出,数据包含在指令编码中,随着指令一起被编译成机器码存储于程序空间中,用“#”作为立即数的前导标识符。ARM Cortex-M4立即数范围为0x00~0xff。例如:
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P59_28510.jpg?sign=1739522942-jLjfqL2GLd0vN1pYDfZBvKXYKEyPB4sa-0-e6be9254e3692dcb188ebb64c731807c)
2)寄存器寻址
在寄存器寻址中,操作数来自于寄存器。例如:
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P59_28511.jpg?sign=1739522942-gugLcdzxhReTzSuap1RAvoKsPPaEm8uc-0-e4ec8c1f65d0c275bfd7710fd0415c6f)
3)直接寻址
在直接寻址方式中,操作数来自于存储单元,指令中直接给出存储单元地址。指令码中,显示给出数据的位数,有字(4字节)、半字(2字节)、单字节3种情况。例如:
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P59_28512.jpg?sign=1739522942-mxNhYrOP84tH5jdm5z1uH5RDIqRa58Ri-0-0e1056c2abb79a465fbcfca5b27baee8)
4)偏移寻址及寄存器间接寻址
在偏移寻址中,操作数来自于存储单元,指令中通过寄存器及偏移量给出存储单元的地址。偏移量不超过4KB(指令编码中偏移量为12位)。偏移量为0的偏移寻址也称为寄存器间接寻址。例如:
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P59_28513.jpg?sign=1739522942-eisYmIKHVSGGSSc9tkJ5weAoCXkMpL3i-0-d305f05a922a18436c1e87cf1e199a51)
2.2.2 数据传送类指令
数据传送类指令的功能有两种情况:一是取存储器地址空间中的数传送到寄存器中;二是将寄存器中的数传送到另一寄存器或存储器地址空间中。数据传送类基本指令有16条。
1. 取数指令
存储器中内容加载(Load)到寄存器中的指令如表2-6所示。其中,LDR、LDRH、LDRB指令分别表示加载来自存储器单元的一个字、半字和单字节(不足部分以0填充);LDRSH和LDRSB指令是指加载存储单元的半字、字节有符号数扩展成32位到指定寄存器Rt。
表2-6 取数指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T59_28515.jpg?sign=1739522942-K1XFAd6Jfn97lCABAMkhDtL9JIUToXM9-0-2d938f1341ce48f1e5acf7c3ede4a010)
在LDM Rn{!},reglist指令中,Rn表示存储器单元起始地址的寄存器;reglist包含一个或多个寄存器,若包含多个寄存器必须以“,”分隔,外面用“{}”标识;“!”是一个可选的回写后缀,reglist列表中包含Rn寄存器时不要回写后缀,否则须带回写后缀“!”。带后缀时,在数据传送完毕之后,最后的地址将写回Rn=Rn+4×(n-1),n为reglist中寄存器的个数。Rn不能为R15,reglist可以为R0~R15的任意组合;Rn寄存器中的值必须字对齐。这些指令不影响N、Z、C、V状态标志。
2. 存数指令
寄存器中内容存储(Store)至存储器中的指令如表2-7所示。STR、STRH和STRB指令存储Rt寄存器中的字、低半字或低字节至存储器单元。存储器单元地址由Rn与Rm之和决定,Rt、Rn和Rm必须为R0~R7之一。
其中,“STM Rn!,reglist”指令将reglist列表寄存器内容以字存储至Rn寄存器中的存储单元地址。以4字节访问存储器地址单元,访问地址从Rn寄存器指定的地址值到Rn+4×(n-1),n为reglist中寄存器的个数。按寄存器编号递增顺序访问,最低编号使用最低地址空间,最高编号使用最高地址空间。对于STM指令,若reglist列表中包含了Rn寄存器,则Rn寄存器必须位于列表首位。如果列表中不包含Rn,则将位于Rn+4×n地址回写到Rn寄存器中。这些指令不影响N、Z、C、V状态标志。
表2-7 存数指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T60_28519.jpg?sign=1739522942-nnnQsfQXDpe67u5R9fL4bwh05y1YiR68-0-4ccbf207b50ccc5c49af35872bb41c74)
3. 寄存器间数据传送指令
如表2-8所示,MOV指令中,Rd表示目标寄存器;imm为立即数,范围为0x00~0xff。当MOV指令中Rd为PC寄存器时,丢弃第0位;当出现跳转时,传送值的第0位清零后的值作为跳转地址。虽然MOV指令可以用作分支跳转指令,但强烈推荐使用BX或BLX指令。这些指令影响N、Z状态标志,但不影响C、V状态标志。
表2-8 寄存器间数据传送指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T61_28521.jpg?sign=1739522942-gcWe1qXmNa5qAsO6L637znlFL3SfhOmn-0-a2d06f22e7ecfd069bb81ac6f0325cc5)
4. 堆栈操作指令
堆栈(Stack)操作指令如表2-9所示。PUSH指令将寄存器值存于堆栈中,最低编号寄存器使用最低存储地址空间,最高编号寄存器使用最高存储地址空间;POP指令将值从堆栈中弹回寄存器,最低编号寄存器使用最低存储地址空间,最高编号寄存器使用最高存储地址空间。执行PUSH指令后,更新SP寄存器值SP=SP-4;执行POP指令后更新SP寄存器值SP=SP+4。若POP指令的reglist列表中包含了PC寄存器,在POP指令执行完成时跳转到该指针PC所指地址处。该值最低位通常用于更新xPSR的T位,此位必须置1,才能确保程序正常运行。
表2-9 堆栈操作指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T61_28523.jpg?sign=1739522942-zU8kIA2GfC7K3X9v1IeK4B2FWQZbtVbM-0-bd72aa4c20a700021ae512e75961607f)
例如:
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P61_28719.jpg?sign=1739522942-yv0qmU9dzYfnj7IPvV375eYQkL4ynPt6-0-67e022c19a1584e1c691d2232965a2e2)
5. 生成与指针PC相关地址指令
如表2-10所示,ADR指令将指针PC值加上一个偏移量得到的地址写进目标寄存器中。若利用ADR指令生成的目标地址用于跳转指令BX、BLX,则必须确保该地址最后一位为1。Rd为目标寄存器,label为与指针PC相关的表达式。在该指令下,Rd必须为R0~R7,数值必须字对齐且在当前PC值的1020字节以内。此指令不影响N、Z、C、V状态标志。这条指令主要提供编译阶段使用,一般可看成一条伪指令。
表2-10 ADR指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T61_28720.jpg?sign=1739522942-cP85SUgSJUNGbzbhbqz0VSIivGJHyaPM-0-5eaa94ac55dc5a0cef2c4d96d19e8fc1)
2.2.3 数据操作类指令
数据操作主要指算术运算、逻辑运算、移位等。
1. 算术运算类指令
(1)算术运算类指令有加、减、乘、比较等,如表2-11所示。
表2-11 算术运算类指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T62_28526.jpg?sign=1739522942-29FsPnKCsGkjuXSM8d9qh71T95RRQQx0-0-0db5411769a8230f218d61ba9873ad29)
(2)加、减指令对操作数的限制条件,如表2-12所示。
表2-12 ADC、ADD、RSB、SBC和SUB操作数限制条件
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T62_28528.jpg?sign=1739522942-vuHlUGq2j70HroPnhhaMKoLGu38K1yEQ-0-a9909a253ebf2182f12a10c62424b821)
2. 逻辑运算类指令
逻辑运算类指令如表2-13所示。AND、EOR和ORR指令把寄存器Rn、Rm值逐位与、异或和或操作;BIC指令是将寄存器Rn的值与Rm的值的反码按位做逻辑“与”操作,结果保存到Rd。这些指令更新N、Z状态标志,不影响C、Z状态标志。
表2-13 逻辑运算类指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T63_28530.jpg?sign=1739522942-SiHTMqetAB5CiNv0aFaYLVWd7kMq2p8M-0-6a7eeb59af9353de7c94a33210246b22)
Rd、Rn和Rm必须为R0~R7,其中Rd为目标寄存器,Rn为存放第一个操作数寄存器,且必须和目标寄存器Rd一致(即Rd就是Rn),Rm为存放第二个操作数寄存器。
3. 移位类指令
移位类指令如表2-14所示。ASR、LSL、LSR和ROR指令,将寄存器Rm的值由寄存器Rs或立即数imm决定移动位数,执行算术右移、逻辑左移、逻辑右移和循环右移。这些指令中,Rd、Rm、Rs必须为R0~R7。对于非立即数指令,Rd和Rm必须一致。Rd为目标寄存器,若省去Rd,表示其值与Rm寄存器一致;Rm为存放被移位数据寄存器;Rs为存放移位长度寄存器;imm为移位长度,ASR指令移位长度范围为1~32,LSL指令移位长度范围为0~31,LSR指令移位长度范围为1~32。
表2-14 移位指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T63_28532.jpg?sign=1739522942-q0vprJGCBXMwvSTutNCSulOBP1YJigJ9-0-810fcb7fcd88a810096cf92fffb21394)
1)单向移位指令
算术右移指令ASR指令比较特别,它把要操作的字节当作有符号数,而符号位(b31)保持不变,其他位右移一位,即首先将b0位移入C中,其他位(b1~b31)右移一位,相当于操作数除以2。为了保证符号不变,ASR指令使符号位b31返回本身。逻辑右移指令LSR把32位操作数右移一位,首先将b0位移入C中,其他右移一位,0移入b31。根据结果,ASR、LSL、LSR指令对标志位N、Z有影响,最后移出位更新C标志位。
2)循环移位指令
在循环右移指令ROR中,将b0位移入b31中的同时也移入C中,其他位右移一位。根据结果,ROR指令对标志位N、Z有影响,最后移出位更新C标志位。
4. 位测试指令
位测试指令如表2-15所示。
表2-15 位测试指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T64_28534.jpg?sign=1739522942-6grqSHqAqiWJJZZXdoJox0brweploi1X-0-ff080a728162dfae9251d407366c31a1)
5. 数据序转指令
数据序转指令如表2-16所示,该指令用于改变数据的字节顺序。Rn为源寄存器,Rd为目标寄存器,且必须为R0~R7之一。REV指令将32位大端数据转小端存放或将32位小端数据转大端存放;REV16指令将一个32位数据划分为两个16位大端数据,将这两个16位大端数据转小端存放或将一个32位数据划分为两个16位小端数据,将这两个16位小端数据转大端存放;REVSH指令将16位带符号大端数据转为32位带符号小端数据,或者将16位带符号小端数据转为32位带符号大端数据,如图2-4所示。这些指令不影响N、Z、C、V状态标志。
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P64_4903.jpg?sign=1739522942-jWzNiPiswDNJOXRuqyWMG7QECx4MBCAH-0-817c0a5048c81b9b8dca7049c4eab015)
图2-4 反序操作
表2-16 数据序转指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T64_28536.jpg?sign=1739522942-pMI6Z2stsnEKMMligeIWVXUmsAmGAMgE-0-e9eb85860e3561fcd7aecb962ff9a34c)
6. 扩展类指令
扩展类指令如表2-17所示。寄存器Rm存放待扩展操作数;寄存器Rd为目标寄存器;Rm、Rd必须为R0~R7。这些指令不影响N、Z、C、V状态标志。
表2-17 扩展类指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T65_28538.jpg?sign=1739522942-gGOhTmXb5MMFaCOdW4kuECpmzzIJIOUY-0-513772b32063adc4e01d8670dea1dc72)
2.2.4 跳转控制类指令
跳转控制类指令如表2-18所示,这些指令不影响N、Z、C、V状态标志。
表2-18 跳转控制类指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T65_28540.jpg?sign=1739522942-6lPPV8dUBCDWadr7b7KFoCgETv5Ub6co-0-c86c53d0b3c8a1c0fd641cbac62fdce1)
跳转控制类指令举例如下,特别注意BL用于调用子程序。
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-P65_28724.jpg?sign=1739522942-REBQvkLvcXVBE77shv8Mau11KwlOb8ZQ-0-7532a7691407a81718809676571c5b2a)
B指令所带条件众多,形成不同条件下的跳转,但只在前256字节至后254字节地址范围内跳转。B指令所带的条件如表2-19所示。
表2-19 B指令所带的条件
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T65_28727.jpg?sign=1739522942-juGXUEAT0helUFy5f06EYZkkx8tbUfD2-0-2188a3e6bd89e4756d9259fb56219f21)
2.2.5 其他指令
未列入数据传输类、数据操作类、跳转控制类三大类的指令,归为其他指令,如表2-20所示。其中,spec_reg表示特殊寄存器,如APSR、IPSR、EPSR、IEPSR、IAPSR、EAPSR、PSR、MSP、PSP、PRIMASK或CONTROL。
表2-20 其他指令
![](https://epubservercos.yuewen.com/2B70D2/17214368204801306/epubprivate/OEBPS/Images/Figure-T66_28545.jpg?sign=1739522942-lNUfAhG9i31SyUJAW1jNl9TOX7Dxd2Bp-0-76916cf2514e6f2e42b8a7033973909a)
表中的中断指令(禁止总中断指令“CPSIE i”,使能总中断指令“CPSID i”)为编程必用指令,实际编程时,由宏函数给出。
下面对两条休眠指令WFE与WFI做简要说明。这两条指令均只用于低功耗模式,并不产生其他操作(这一点类似于NOP指令)。休眠指令WFE执行情况由事件寄存器决定。若事件寄存器为零,只有在发生如下事件时才执行:①发生异常,且该异常未被异常屏蔽寄存器或当前优先级屏蔽;②在进入异常期间,系统控制寄存器的SEVONPEND置位;③若使能调试模式时,触发调试请求;④外围设备发出一个事件或在多重处理器系统中另一个处理器使用SVC指令。若事件寄存器为1,WFE指令清该寄存器后立刻执行。休眠指令WFI执行条件为:发生异常,或PRIMASK.PM被清0,产生的中断将会先占,或者发生触发调试请求(不论调试是否被使能)。