前面已经向读者介绍过在ARM体系结构中支持两种指令集:32位的ARM指令集和16位的Thumb指令集。只有遵循一定的操作规则,Thumb程序代码和ARM程序代码才可以相互切换调用。
虽然从前面的内容中可以看出,ARM指令具有较高的执行效率。但在部分特定的场合中,特别是在对代码密度有较高要求的场合中,仍然需要使用Thumb指令集。
Thumb指令集是ARM指令集的一个子集,主要解决ARM程序代码的密度问题。由于Thumb指令使用标准的ARM寄存器配置进行操作,因此ARM指令集和Thumb指令集具有良好的互通性。
Thumb指令集与ARM指令集相比具有以下特性:
(1)Thumb指令集中的指令不能使用-S后缀来影响CPSR寄存器中的标志;
(2)Thumb指令集中只有一条分支指令可以实现条件选择,而其他指令均为无条件指令;
(3)Thumb指令集中的字长为16位,因此立即数的范围比ARM中立即数的范围要小很多;
(4)实现同样功能的代码,Thumb指令集代码需要的存储空间大约为ARM指令集代码的70%;
(5)实现同样功能的代码,Thumb指令集代码中的指令数量大约比ARM指令集代码中的指令数量多30%;
(6)如果使用16位的存储器,Thumb指令的处理速度比ARM指令的处理速度快约50%;
(7)如果使用32位的存储器,ARM指令的处理速度比Thumb指令的处理速度快约40%;
(8)在系统功耗上,Thumb指令集比ARM指令集节电约30%。
从上述Thumb指令的种种特性可以看出,Thumb指令集主要适合使用在一些资源比较缺乏,代码效率要求比较高的场合。但这些也是以处理器的执行速度和性能为代价的。
在实际工程应用中,如果ARM嵌入式系统对系统的性能有比较高的要求,则应该选用ARM指令集;如果对系统的成本和功耗有比较高的要求,则应该选用Thumb指令集。当然,也可以将ARM指令集和Thumb指令集混合使用,发挥各自的特点。
和ARM指令类似,Thumb指令也具有自己独特的代码结构。虽然在实际的工程设计中,用户并不需要熟记Thumb指令集中的代码内容,但应该对指令集中的代码结构有比较清楚的了解。这样可以深刻理解Thumb指令的功能和具体操作时的注意点。
从表2.12可以看出,Thumb指令集的代码结构大致可以分为以下几个部分。
(1)操作码。在第一条指令中,第15~11位为指令的操作码,用于决定当前操作指令的类型。
(2)立即数。在第一条指令中,第10~6位为指令的立即数,用于在指令中直接设定操作数。
(3)寄存器。在表2.12所示的Thumb指令格式中,Rm、Rn和Rd都是通用的寄存器符号,用于指定相关的通用寄存器。
(4)条件码。在表2.12所示的Thumb指令格式中,cond为指令的条件码。与ARM指令集不同是,在Thumb指令集中只有一条指令具有条件码,即转移指令B。而其他指令均无条件码。
(5)寄存器组。在表2.12所示的Thumb指令格式中,registers为指令的寄存器组。用于指定一组寄存器,在批量数据操作时用于指令相关的一组寄存器。
下面将通过一个Thumb指令的具体结构操作来说明指令结构与程序代码之间的对应关系。
表2.12 Thumb指令的格式
【例32】已知算术右移指令ASR的代码结构如表2.12中序号1所表示的形式。查看ASR指令的一般格式及代码结构之间的对应关系。
由于ASR指令的代码结构如序号1所表示的形式,因此,只要将上述指令中的参数逐一填写到指令结构的框架中即可,具体如图2.12所示。
图2.12 Thumb指令集中ASR指令的结构
Thumb指令集是ARM指令集的一个子集,因此Thumb状态下的寄存器也是ARM状态下寄存器的一个子集。在Thumb指令集中,程序代码可以直接访问8个通用寄存器(R0~R7)、程序计数器PC、栈指针SP、链接寄存器LR和状态寄存器CPSR。
需要注意的是,Thumb状态下的寄存器与ARM状态下的寄存器关系如下:
(1)Thumb状态下和ARM状态下的通用寄存器R0~R7是相同的;
(2)Thumb状态下和ARM状态下的CPSR寄存器和SPSR寄存器是相同的;
(3)Thumb状态下的堆栈寄存器SP对应于ARM状态下的R13;
(4)Thumb状态下的链接寄存器LR对应于ARM状态下的R14;
(5)Thumb状态下的程序计数器PC对应于ARM状态下的R15。
值得用户特别注意的是,在Thumb状态下,寄存器R8~R15并不是标准寄存器中的一部分的,但也可以访问这些寄存器。
在Thumb指令集中,按照指令的功能可以大致分为以下几类。
(1)跳转指令:用于控制程序的执行流程,以及在ARM代码模式和Thumb代码模式之间的切换。
(2)算术运算指令:用于进行乘法、加法、减法等算术运算。
(3)逻辑运算指令:用于对操作数进行逻辑操作,如“与”操作、“或”操作,以及“非”操作等。
(4)存储器访问指令:用于控制存储器和寄存器之间的数据传送。
(5)数据传送指令:用于操作片上ALU、桶形移位器、乘法器,以及完成通用寄存器之间的高速数据处理。
(6)异常产生指令:用于控制软件的异常。
(7)移位指令:用于控制操作数的移位操作,包括算术移位操作和逻辑移位指令
从Thumb指令的功能分类来看,与ARM指令的功能分类完全类似,且具有一致的数据操作功能。Thumb指令集中的指令基本上与ARM指令集中的指令类似。不同的是,Thumb指令集中的指令都是16位的,因此Thumb指令在编码格式、跳转目标地址范围方面与ARM指令集有所不同。因此用户可以参照ARM指令集的内容,这里就不再重复解释Thumb指令的功能了。
本小节主要介绍了ARM处理器中的Thumb指令集。Thumb指令集在功能上是ARM指令集的子集。需要说明的是,Thumb指令集中的每一条指令都可以在ARM指令集中找到与其对应的指令。
由于Thumb指令集只使用了ARM指令集一般的宽度(16位)来实现同样的功能,所以Thumb指令的语法定义肯定要比ARM指令少。为了实现同样的功能,使用Thumb指令编写的代码肯定要比使用ARM指令编写的代码具有更多的代码行。尽管如此,在实现同样功能的前提下,Thumb指令使用的代码空间要比ARM指令使用的代码空间要小。
在进行ARM系统设计时,当外部存储设备为16位时,Thumb指令集的优势就会比较明显。如果ARM嵌入式系统侧重于系统的性能,则应该选用32位的ARM指令。如果ARM嵌入式系统侧重于成本和功耗,则应该选用16位的Thumb指令。如果用户能够将这两个指令集集合使用,发挥各自的特点,将会进一步提高ARM代码的效率。