与人类语言类似,计算机编程语言也包括字、词、句和段。例如,在C语言中,各种类型的变量、常量、运算符(如赋值符“=”、大于“>”等)、关键字(如if、else等)都是“字”,表达式即“词”,语句即“句”,函数、宏定义即“段”;运算符、关键字就是“动词”,变量、常量就是“名词”。ARM汇编语言也是如此:操作数(寄存器、立即数)、操作码和条件描述是“字”,地址模式、带有条件描述的指令是表达式(“词”),每条汇编指令是“句”,函数及宏是“段”。计算机编程语言是软件的载体,而软件与硬件是通过指令集联系在一起的,即指令集是计算机硬件和软件的接口,如图2-18所示。
图2-18 软件、硬件和指令集之间的关系
ARM指令集是加载/存储(Load/Store)型的32位指令集,仅能处理寄存器中的数据,处理结果都要送回寄存器,对系统存储器的访问需要通过专门的加载/存储指令来完成。ARM指令集可以分为跳转指令、数据处理指令、程序状态寄存器(P SR)处理指令、加载/存储指令、协处理器指令和异常产生指令六大类。ARM指令集与x86指令集的对比如表2-13所示。
表2-13 ARM指令集与x86指令集的对比
在使用方面,ARM指令的格式也要比x86复杂一些。通常一条ARM指令有如下形式:
其中,<opcode>是指令助记符,必有项,决定了指令的操作,如ADD表示算术加操作指令。{<cond>}是指令执行的条件,可选项。{S}决定指令的操作是否影响CPSR的值,可选项。<Rd>是目标寄存器,必有项。<Rn>是包含第1个操作数的寄存器,当仅需要一个源操作数时可省略,必有项。{Operand2}是第2个操作数,可选项。第2个操作数有两种格式,即#immed_8r和Rm{,Shift}。
〖说明〗 Rm可以在指令执行前进入桶形移位器进行移位操作,而Rn则会直接进入ALU。
ARM指令的寻址方式包括立即寻址、寄存器寻址、寄存器间接寻址、基址加变址寻址、堆栈寻址、块复制寻址和相对寻址。
ARM指令系统是RISC指令集,指令系统优先选取使用频率高的指令,以及一些有用但不复杂的指令,指令长度固定,指令格式种类少,寻址方式少,只有存取指令可以访问存储器,其他指令都在寄存器之间操作,且大部分指令都在一个周期内完成,以硬布线控制逻辑为主,不用或少用代码控制。ARM更容易实现流水线等操作。ARM采用长乘法指令和增强的DSP指令等指令类型,使得ARM集合了RISC和CISC的优势。同时,ARM采用了快速中断响应、虚拟存储系统支持、高级语言支持、定义不同的操作模式等,使得其功能更为强大。
Thumb指令集是ARM指令集的一个子集,其指令长度为16位。与等价的32位代码相比,Thumb指令集在保留32位代码优势的同时,大大节省了系统的存储空间。
所有的Thumb指令都有对应的ARM指令,而且Thumb的编程模型与ARM的编程模型对应。在应用程序的编写过程中,只要遵循一定的调用规则,Thumb子程序和ARM子程序就可以互相调用。当处理器执行ARM程序段时,称ARM处理器处于ARM工作状态;当处理器执行Thumb程序段时,称ARM处理器处于Thumb工作状态。
与ARM指令集相比较,Thumb指令集中的数据处理指令的操作数仍然是32位,指令地址也是32位,但Thumb指令集为了实现16位的指令长度,舍弃了ARM指令集的一些特性,如大多数的Thumb指令都是无条件执行的,而几乎所有的ARM指令都是有条件执行的;大多数的Thumb数据处理指令的目的寄存器与其中一个源寄存器相同。Thumb指令的条数较ARM指令多,为了完成相同的工作,ARM可能只用一条指令,而Thumb需要用多条指令。在一般情况下,Thumb指令与ARM指令的时间效率和空间效率如下。
Thumb代码所需的存储空间为ARM代码的60%~70%。
Thumb代码使用的指令数比ARM代码多30%~40%。
若使用32位存储器,则ARM代码比Thumb代码快约40%。
若使用16位存储器,则Thumb代码比ARM代码快40%~50%。
与ARM代码相比,若使用Thumb代码,则存储器的功耗会降低约30%。
显然,ARM指令集和Thumb指令集各有其优点:若对系统的性能有较高要求,则应使用32位存储系统和ARM指令集;若对系统的成本及功耗有较高要求,则应使用16位存储系统和Thumb指令集。当然,若二者结合使用,充分发挥其各自的优点,则会取得更好的效果。
ARM指令集的发展简图如图2-19所示。由图2-19可见,每一代体系结构都会增加新技术。为兼容数据总线宽度为16位的应用系统,ARM体系结构除了支持执行效率很高的32位ARM指令集,还支持16位Thumb指令集,从而形成Thumb-2指令集。CM3只使用Thumb-2指令集。这是个很大的突破,因为它允许32位指令和16位指令优势互补(体现CISC特点),代码密度与处理性能兼顾。
图2-19 ARM指令集的发展简图
Thumb-2指令集是一个突破性的指令集,它强大、易用、高效。Thumb-2指令集是16位Thumb指令集的一个超集,在Thumb-2指令集中,16位指令首次与32位指令并存,结果在Thumb工作状态下指令集功能增强,同时指令周期数也明显减少。Thumb-2指令集可以在单一的操作模式下完成所有处理,它使CM3在多方面都比传统的ARM处理器先进,既没有状态切换的额外开销(节省了执行时间和指令空间),又不需要把源代码文件分成按ARM编译和按Thumb编译(软件开发的管理工作大大减少),更无须反复地求证和测试究竟该在何时、何地切换到何种状态下程序才最有效率(开发软件更容易)。利用Thumb-2指令集编写的程序占用的存储空间较小,代码空间可以减少约70%,而且功耗也下降很多。Thumb-2指令集能够更有效地使用高速缓存,由于在嵌入式系统中,高速缓存资源是非常少的,因此会提高系统的整体性能,不仅提高了运行速度,还减少了代码的读取次数。
图2-20 Thumb-2指令集与Thumb指令集的关系
需要说明的是,CM3并不支持所有的Thumb-2指令,ARMv7-M的说明书只要求实现Thumb-2指令集的一个子集,如图2-20所示。举例来说,协处理器指令就被裁剪掉了(可以使用外部的数据处理引擎来替代)。CM3也没有实现SIMD指令集。附录B给出了CM3指令清单。
对于Thumb-2指令集,建议初学者利用英文还原法记忆指令功能,当看到一段汇编代码时,查找相关的指令集,理解代码的意图和作用。
下面3段汇编程序是将同一段C语言代码分别编译成ARM、Thumb和Thumb-2指令得到的。
ARM指令集汇编程序:
Thumb指令集汇编程序:
Thumb-2指令集汇编程序:
从上面这3段功能相同的汇编代码可以大致看出ARM、Thumb和Thumb-2指令集的特点,如表2-14所示。
表2-14 ARM、Thumb和Thumb-2指令集对比
由表2-14可以看出,ARM指令集的汇编代码全部为32位,每条指令能承载的信息较多,可以使用较少的指令完成相应的功能,在相同频率下运行速度较快,但因每条指令较长,所以占用的存储空间较大;Thumb指令集的汇编代码全部为16位,每条指令能承载的信息较少,需要使用较多的指令才能完成相应的功能,在相同频率下运行速度较慢,但它占用的存储空间较小;Thumb-2指令集在ARM指令集与Thumb指令集之间取了一个平衡,兼顾二者的优势,既加快了运行速度(尽可能用一条指令来完成每个操作),又节省了存储空间(尽可能用较短的指令来完成每个操作)。