ARM指令集与Thumb指令集--区别关联--汇编指令 BX LR ; 跳转回LR地址处,既可以是ARM模式也可以是Thumb模式

BX        LR    ; 跳转回LR地址处,既可以是ARM模式也可以是Thumb模式

A

一、现在先区分下ARM指令集与Thumb指令集
       Thumb 指令可以看作是 ARM 指令压缩形式的子集,是针对代码密度的问题而提出的,它具有 16 位的代码密度但是它不如ARM指令的效率高 .Thumb 不是一个完整的体系结构,不能指望处理只执行Thumb 指令而不支持 ARM 指令集.因此,Thumb 指令只需要支持通用功能,必要时可以借助于完善的 ARM 指令集,比如,所有异常自动进入 ARM 状态.在编写 Thumb 指令时,先要使用伪指令 CODE16 声明,而且在 ARM 指令中要使用 BX指令跳转到 Thumb 指令,以切换处理器状态.编写 ARM 指令时,则可使用伪指令 CODE32声明.

流水线处理:
不同于微编码的处理器,ARM (保持它的 RISC 性)是完全硬布线的。

为了加速 ARM 2 和 3 的执行使用 3 阶段流水线。第一阶段持有从内存中取回的指令。第二阶段开始解码,而第三阶段实际执行它。故此,程序计数器总是超出当前执行的指令两个指令。(在为分支指令计算偏移量时必须计算在内)。

因为有这个流水线,在分支时丢失 2 个指令周期(因为要重新添满流水线)。所以最好利用条件执行指令来避免浪费周期。例如:

...
CMP R0,#0
BEQ over
MOV R1,#1
MOV R2,#2
over
...


可以写为更有效的:
...
CMP R0,#0
MOVNE R1,#1
MOVNE R2,#2


二、Thumb 指令集与 ARM 指令集的区别
Thumb 指令集没有协处理器指令,信号量指令以及访问 CPSR 或 SPSR 的指令,没有乘加指令及 64 位乘法指令等,且指令的第二操作数受到限制;除了跳转指令 B 有条件执行功能外,其它指令均为无条件执行;大多数 Thumb 数据处理指令采用 2 地址格式.Thumb指令集与 ARM 指令的区别一般有如下几点:
      跳转指令
程序相对转移,特别是条件跳转与 ARM 代码下的跳转相比,在范围上有更多的限制,转向子程序是无条件的转移.
      数据处理指令
数据处理指令是对通用寄存器进行操作,在大多数情况下,操作的结果须放入其中一个操作数寄存器中,而不是第 3 个寄存器中.数据处理操作比 ARM 状态的更少,访问寄存器 R8~R15 受到一定限制.除 MOV 和 ADD 指令访问器 R8~R15 外,其它数据处理指令总是更新 CPSR 中的 ALU 状态标志.访问寄存器 R8~R15 的 Thumb 数据处理指令不能更新 CPSR 中的 ALU 状态标志.
      单寄存器加载和存储指令
在 Thumb 状态下,单寄存器加载和存储指令只能访问寄存器 R0~R7
      批量寄存器加载和存储指令
LDM 和 STM 指令可以将任何范围为 R0~R7 的寄存器子集加载或存储. PUSH 和 POP 指令使用堆栈指令 R13 作为基址实现满递减堆栈.除 R0~R7 外,PUSH 指令还可以存储链接寄存器 R14,并且 POP 指令可以加载程序指令PC

ARM指令分为以下几种:

一、ARM 存储器访问指令
助记符                       说明                                        操作                                                  条件码位置
LDR    Rd,addressing      加载字数据                            Rd←[addressing],addressing 索引 LDR{cond}
LDRB   Rd,addressing    加载无符字节数据                  Rd←[addressing],addressing 索引 LDR{cond}B
LDRT   Rd,addressing    以用户模式加载字数据        Rd←[addressing],addressing 索引 LDR{cond}T
LDRBT Rd,addressing    以用户模式加载无符号字数据 Rd←[addressing],addressing 索引 LDR{cond}BT
LDRH   Rd,addressing    加载无符半字数据              Rd←[addressing],addressing 索引 LDR{cond}H
LDRSB Rd,addressing    加载有符字节数据        Rd←[addressing],addressing 索引 LDR{cond}SB
LDRSH Rd,addressing    加载有符半字数据     Rd←[addressing],addressing 索引 LDR{cond}SH
STR    Rd,addressing    存储字数据                        [addressing]←Rd,addressing 索引 STR{cond}
STRB   Rd,addressing    存储字节数据       [addressing]←Rd,addressing 索引 STR{cond}B
STRT   Rd,addressing    以用户模式存储字数据    [addressing]←Rd,addressing 索引 STR{cond}T
SRTBT Rd,addressing    以用户模式存储字节数据   [addressing]←Rd,addressing 索引 STR{cond}BT
STRH   Rd,addressing    存储半字数据          [addressing]←Rd,addressing 索引 STR{cond}H
LDM{mode} Rn{!},reglist   批量(寄存器)加载       reglist←[Rn…],Rn 回存等          LDM{cond}{more}
STM{mode} Rn{!},rtglist   批量(寄存器)存储           [Rn…]← reglist,Rn 回存等         STM{cond}{more}
SWP     Rd,Rm,Rn          寄存器和存储器字数据交换 Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm) SWP{cond}
SWPB    Rd,Rm,Rn        寄存器和存储器字节数据交换 Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm) SWP{cond}B

二、ARM 数据处理指令
助记符号                                   说明                                   操作               条件码位置
MOV Rd ,operand2   数据转送                           Rd←operand2               MOV {cond}{S}
MVN Rd ,operand2   数据非转送                        Rd←(operand2)             MVN {cond}{S}
ADD Rd,Rn operand2 加法运算指令                  Rd←Rn+operand2            ADD {cond}{S}
SUB Rd,Rn operand2 减法运算指令                  Rd←Rn-operand2            SUB {cond}{S}
RSB Rd,Rn operand2 逆向减法指令                  Rd←operand2-Rn            RSB {cond}{S}
ADC Rd,Rn operand2 带进位加法                     Rd←Rn+operand2+carry      ADC {cond}{S}
SBC Rd,Rn operand2 带进位减法指令            Rd←Rn-operand2-(NOT)Carry SBC {cond}{S}
RSC Rd,Rn operand2 带进位逆向减法指令       Rd←operand2-Rn-(NOT)Carry RSC {cond}{S}
AND Rd,Rn operand2 逻辑与操作指令              Rd←Rn&operand2            AND {cond}{S}
ORR Rd,Rn operand2 逻辑或操作指令             Rd←Rn|operand2            ORR {cond}{S}
EOR Rd,Rn operand2 逻辑异或操作指令          Rd←Rn^operand2            EOR {cond}{S}
BIC Rd,Rn operand2 位清除指令                      Rd←Rn&(~operand2)         BIC {cond}{S}
CMP Rn,operand2    比较指令                       标志 N、Z、C、V←Rn-operand2 CMP {cond}
CMN Rn,operand2    负数比较指令               标志 N、Z、C、V←Rn+operand2 CMN {cond}
TST Rn,operand2    位测试指令                    标志 N、Z、C、V←Rn&operand2 TST {cond}
TEQ Rn,operand2    相等测试指令                标志 N、Z、C、V←Rn^operand2 TEQ {cond}

三、乘法指令
      具有 32×32 乘法指令,32×32 乘加指令,32×32 结果为 64 位的乘/乘法指令.
助记符                                               说明                        操作              条件码位置
MUL   Rd,Rm,Rs        32 位乘法指令    Rd←Rm*Rs           (Rd≠Rm)    MUL{cond}{S}
MLA   Rd,Rm,Rs,Rn     32 位乘加指令    Rd←Rm*Rs+Rn        (Rd≠Rm)    MLA{cond}{S}
UMULL RdLo,RdHi,Rm,Rs 64 位无符号乘法指令 (RdLo,RdHi)←Rm*Rs             UMULL{cond}{S}
UMLAL RdLo,RdHi,Rm,Rs 64 位无符号乘加指令 (RdLo,RdHi)←Rm*Rs+(RdLo,RdHi) UMLAL{cond}{S}
SMULL RdLo,RdHi,Rm,Rs 64 位有符号乘法指令 (RdLo,RdHi)←Rm*Rs             SMULL{cond}{S}
SMLAL RdLo,RdHi,Rm,Rs 64 位有符号乘加指令 (RdLo,RdHi)←Rm*Rs+(RdLo,RdHi) SMLAL{cond}{S}

四、跳转指令
在 ARM 中有两种方式可以实现程序的跳转,一种是使用跳转指令直接跳转,另一种则是直接向 PC 寄存器赋值实现跳转.
          
助记符           说明                            操作                    条件码位置
B label 跳转指令                             Pc←label                 B{cond}
BL label 带链接的跳转指令             LR←PC-4, PC←label BL{cond}
BX Rm    带状态切换的跳转指令    PC←label,切换处理状态 BX{cond}

五、ARM协处理器指令
ARM 支持协处理器操作,协处理器的控制要通过协处理器命令实现.
助记符                                                            说明                           操作             条件码位置
CDP
coproc,opcodel,CRd,CRn,CRm{,opcode2}     协处理器数据操作指令       取决于协处理器   CDP{cond}
LDC{L} coproc,CRd〈地址〉                  协处理器数据读取指令      取决于协处理器   LDC{cond}{L}
STC{L} coproc,CRd,〈地址〉                 协处理器数据写入指令      取决于协处理器   STC{cond}{L}
                                                                    ARM 寄存器到协处理器
MCR coproc, opcodel,Rd,CRn,{,opcode2}   寄存器的数据传送指令       取决于协处理器 MCR{cond}
                                                                     协处理器寄存器到 ARM
MRC coproc, opcodel,Rd,CRn,{,opcode2}   寄存器到数据传送指令        取决于协处理器MCR{cond}

五、ARM 杂项指令
助记符                                                说明                            操作                               条件码位置
SWI immed_24                软中断指令               产生软中断,处理器进入管理模式       SWI{cond}
MRS Rd,psr                  读状态寄存器指令 Rd←psr,psr 为 CPSR 或 SPSR                  MRS{cond}
MSR psr_fields,Rd/#immed_8r 写状态寄存器指令 psr_fields←Rd/#immed_8r,psr 为 CPSR 或 SPSR MSR{cond}


 

B

由于Thumb指令在某些特殊情况下可能比ARM指令更有效,所以它在很多方面得到了广泛的应用。但是Thumb知识ARM指令集的一个子集,它不能独立组成一个应用系统,所以在很多情况下应用程序需要二者的混合编程,这就必然存在ARM与Thumb状态之间函数调用的问题。下面将分别详细介绍。      状态切换的实现ARM/Thumb之间的状态切换是通过一条专用的转移交换指令BX来实现的。BX指令以通用寄存器位操作数,通过拷贝Rn到PC来实现4GB空间范围内的一个绝对跳转。BX利用Rn寄存器中目的地址值的最后一位来判断跳转后的状态。当最后一位为0时,表示转移到ARM状态;当最后一位为1时,表示转移到Thumb状态。如图所示无论是ARM还是Thumb,其指令在存储器中都是边界对齐的。(2字节或者4字节对齐,最低位不起作用!)因此,在执行跳转过程中,PC寄存器中的最低位被舍弃,不起作用。在BX指令的执行过程中,最低位正好被用作状态判断的标志,不会造成存储器访问不对齐的错误。下面是一段直接进入状态切换的例程:                                                                     ;从ARM状态开始  CODE32                                                         ;表明一下是ARM指令         ADR       R0,Into_Thumb+1                    ;得到目标地址,末位置1,表示转移到Thumb         BX         R0                                             ;转向Thumb                …  CODE16                                                         ;表明以下是Thumb指令Into_Thumb         …         ADR       R5,Back_to_ARM                       ;得到目标地址,末位缺省为0 ,转移到ARM         BX         R5                                             ;转向ARM         …  CODE32         Back_to_ARM                                          ;ARM代码段起始地址举例:从ARM态进入thumb态① 将在Makefile中将.c文件编译指定为thumb态参考:https://www.cnblogs.com/QuLory/archive/2012/10/23/2735226.html%.o:%.c    arm-linux-gcc -mthumb -c -o $@ $^ -fno-builtin    %.o:%.S    arm-linux-gcc -c -o $@ $^.S文件直接在文件中修改来实现态的转化② 修改.S文件从arm转化到thumb态.text.global _start.code 32_start:    /* 怎样从arm_state -> thumb_state */    adr r0,thumb_func    add r0,r0,#1    bx r0    .code 16thumb_func:        bl sdram_init    //bl sdram_init2 //用到有初始值的数组,不是位置无关码        bl copy2sdram        bl clean_bss     //bl main //使用BL命令相对跳转,程序仍然在Nor/sram执行    ldr r0,=main //绝对跳转,跳到SDRAM    mov pc,r0halt:    b halt-----------------------------------------------------------------------------------------------------------------------------------------------------问题:①:start.S: Assembler messages:start.S:60: Error: lo register required -- `ldr pc,=main'Makefile:11: recipe for target 'start.o' failedthumb不像arm态那样,不能直接将标号赋值给pc,需要通过寄存器转化:ldr r0,=mainmov pc,r0②:init.o(.text+0x58): In function `sdram_init2':: undefined reference to `memcpy'thumb中自动给我们将数组中的值通过memcpy复制到了数组,我们可以通过static来解决这个问题:参考Getting GCC to compile without inserting call to memcpy:https://stackoverflow.com/questions/6410595/getting-gcc-to-compile-without-inserting-call-to-memcpyunsigned int arr[]  = {0x02000000,     //BWSCON0x00000700,     //BANKCON00x00000700,     //BANKCON10x00000700,     //BANKCON20x00000700,     //BANKCON3  0x00000700,     //BANKCON40x00000700,     //BANKCON50x00018001,     //BANKCON60x00018005,     //BANKCON70x008404f5,     //REFRESH 0x000000b1,     //BANKSIZE0x00000020,     //MRSRB60x00000020,     //MRSRB7};//把那些值全部放在数组里面 ->>>>>>const static unsigned int arr[]  = {0x02000000,     //BWSCON0x00000700,     //BANKCON00x00000700,     //BANKCON10x00000700,     //BANKCON20x00000700,     //BANKCON3  0x00000700,     //BANKCON40x00000700,     //BANKCON50x00018001,     //BANKCON60x00018005,     //BANKCON70x008404f5,     //REFRESH 0x000000b1,     //BANKSIZE0x00000020,     //MRSRB60x00000020,     //MRSRB7};//把那些值全部放在数组里面③:warning: conflicting types for built-in function解决:在编译的时候加上-fno-builtin不使用内建函数arm-linux-gcc -mthumb -c -o $@ $^ -fno-builtin
 


C

1 thumb指令集概述
为兼容数据总线宽度为16位的应用系统,ARM体系结构除了支持执行效率很高的32位ARM指令集以外,同时支持16位的Thumb指令集。
Thumb指令集是ARM指令集的一个子集,是针对代码密度问题而提出的,它具有16位的代码宽度。与等价的32位代码相比较,Thumb指令集在保留32位代码优势的同时,大大的节省了系统的存储空间。Thumb不是一个完整的体系结构,不能指望处理器只执行Thumb指令集而不支持ARM指令集。
当处理器在执行ARM程序段时,称ARM处理器处于ARM工作状态,当处理器在执行Thumb程序段时,称ARM处理器处于Thumb工作状态(CPSR的T=0:arm,T=1:thumb)。Thumb指令集并没有改变ARM体系底层的编程模型,只是在该模型上增加了一些限制条件,只要遵循一定的调用规则,Thumb子程序和ARM子程序就可以互相调用。
与ARM指令集相比较,Thumb指令集中的数据处理指令的操作数仍然是32位,指令地址也为32位,但Thumb指令集为实现16位的指令长度,舍弃了ARM指令集的一些特性,相比之下从指令集上看thumb和arm主要有以下不同:
l 跳转指令。条件跳转在范围上有更多的限制,转向子程序只具有无条件转移。
l 数据处理指令。对通用寄存器进行操作,操作结果需放入其中一个操作数寄存器,而不是第三个寄存器。
l 单寄存器加载和存储指令。Thumb状态下,单寄存器加载和存储指令只能访问寄存器R0~R7。
l 批量寄存器加载和存储指令。LDM和STM指令可以将任何范围为R0~R7的寄存器子集加载或存储,PUSH和POP指令使用堆栈指针R13作为基址实现满递减堆栈,除R0~R7外,PUSH指令还可以存储链接寄存器R14,并且POP指令可以加载程序指令PC。
Thumb指令集没有包含进行异常处理时需要的一些指令,因此,在异常中断时还是需要使用ARM指令。这种限制决定了Thumb指令不能单独使用需要与ARM指令配合使用。
 2 thumb寄存器和arm寄存器的关系
 
1)、Thumb 状态寄存器集是ARM 状态寄存器集的子集
    程序员可直接访问8 个通用寄存器R0~R7、PC、堆栈指针SP、链接寄存器LR和CPSR。每个特权模式都有分组的SP、LR和SPSR。
2)、Thumb状态寄存器与ARM 状态寄存器的关系
         Thumb状态寄存器与ARM状态寄存器有如下关系:
l Thumb状态R0~R7与ARM状态R0~R7相同。
l Thumb状态CPSR和SPSR与ARM状态CPSR和SPSR 相同。
l Thumb状态SP映射到ARM状态R13。
l Thumb状态LR映射到ARM状态R14。
l Thumb状态PC映射到ARM状态PC(R15)。
3)、在Thumb状态中访问高寄存器
    在Thumb状态中高寄存器(寄存器R0~R7为低寄存器,寄存器R8~R15为高寄存器)不是标准寄存器集的一部分,汇编语言程序员对它们的访问受到限制,但可以将它们用于快速暂存。
    可以使用MOV指令的特殊变量将一个值从低寄存器R0~R7转移到高寄存器R8~R15,或者从高寄存器到低寄存器。CMP指令可用于比较高寄存器和低寄存器的值。ADD 指令可用于将高寄存器的值与低寄存器的值相加。

在编写Thumb指令时,先要使用伪指令CODE16声明,编写ARM指令时,则可使用CODE32伪指令声明。   
1、Thumb指令集没有协处理器指令、信号量指令、以及访问CPSR或SPSR的指令,没有乘加指令及64位乘法指令等,且指令的第二操作数受到限制;
2、大多数的Thumb数据处理指令采用2地址格式; 
3、除了跳转指令B有条件执行功能之外,其他指令均为无条件执行,而且分支指令的跳转范围有更多限制; 
4、数据处理指令是对通用寄存器进行操作,在大多数情况下,操作的结果放入其中一个操作数寄存器中,而不是放入第3个寄存器中;访问寄存器R8~R15受到一定的限制,除MOV、ADD指令访问R8~R15外,其他数据处理指令总是更新CPSR中ALU状态标志,访问寄存器R8~R15的Thumb数据处理指令不能更新CPSR中的ALU状态指示。 
5、Thumb状态下,单寄存器加载和存储指令只能访问寄存器R0~R7; 
6、LDM、STM指令可以将任何范围为R0~R7的寄存器子集加载或存储; 
7、PUSH、POP指令使用栈寄存器R13作为基址堆栈操作。 
    大多数ARM数据处理指令采用的是3地址格式(除了64位乘法指令外)。
所有异常都会使微处理器返回到ARM模式状态,并在ARM的编程模式中处理。由于ARM微处理器字传送地址必须可被4整除(即字对准),半字传送地址必须可被2整除(即半字对准)。而Thumb指令是2个字节长,而不是4个字节,所以,由Thumb执行状态进入异常时其自然偏移与ARM不同。
16位Thumb指令集是从32位ARM指令集提取指令格式的,每条Thumb指令有相同处理器模型所对应的32位ARM指令。
只要遵循ATPCS调用规则,Thumb子程序和ARM子程序就可以互相调用
 

你可能感兴趣的:(XOS)