142011
 

七、ARM9汇编指令系统

1.概述。

        32位ARM指令集由13种基本指令类型组成,分成4大类。
3种类型的存储器访问指令,用于控制存储器和寄存器之间的数据传送。第一种类型用于优化的灵活寻址;第二种类型用于快速上下文切换;第三种类型用于交换数据。
3种类型的数据处理指令,使用片内的累加器(ALU)、桶形移位器和乘法器,对31个寄存器完成高速数据处理操作。
4种类型的分枝指令,用于控制程序执行流程、指令优先级、ARM代码和Thumb代码的切换。
3种类型的协处理器指令,专用于控制外部协处理器。这些指令以开放和统一的方式扩展了指令集的片外功能。 上述句法形式中所用到的符号意义如下:

 
2.存储器访问指令

        (1) LDR和STR —字和无符号字节32位字8位无符号字节(B)加载寄存器(LDR)和存储寄存器(STR)指令。字节写时是用“0”扩展到32位。

LDR和STR指令都有以下4种句法形式:
op  {cond}  {B}  {T}  Rd,[Rn]                              零偏移
op  {cond}  {B}  Rd,[Rn,Flexoffset]  {!}          前索引偏移
op  {cond}  {B}  Rd,label                                   程序相对偏移
op  {cond}  {B}  {T}  Rd,[Rn],Flexoffset  {!}   后索引偏移

op      操作码,后面所用时意义相同。在此代表LDR和STR。
cond  可选条件码,条件码必须是下表中所列的一种。后面所用时意义相同
B        可选后缀。若有B,则传送Rd的最低有效字节,若op是LDR,则Rd的其他字节清零。
T        可选后缀。若有T,则即使处理器是在特权模式下,存储系统也将访问看成处理器是在用户模式下。T在用户模式下无效,不能与前索引偏移一起使用。强制使用用户模式寄存器
Rn     存储器的基址寄存器。后面所用时意义相同。若指令是带写回的前索引(后缀符号为“!”)或后索引,或使用了后缀T,则不允许Rn和Rd相同。如果有“!” 则指令执行后的地址会被写回到Rn寄存器中。
Rd     用于加载/存储操作的ARM寄存器。后面所用时意义相同。Destination。
Flexoffset  加到Rn上的灵活偏移量。该偏移量可以是下面两种形式之一:
#expr                    是取值范围为-4095~+4095的整数,经常是常量或常量表达式
{-} Rm {,shift}    Rm是内含偏移量的寄存器,它不能是R15。shift是Rm的可选移位方法,可以是下列形式中的一种。
ASR n           算术右移n位(1≤n≤32);
LSL n           逻辑左移n位(0≤n≤31);
LSR n           逻辑右移n位(1≤n≤32);
ROR n          循环右移n位(1≤n≤31);
RRX              循环右移1位,带扩展。
这里是对Rm移位后,与Rn进行+/-运算。

label  程序相对偏移表达式。偏移量必须是在当前指令的上下4KB范围内。
!          可选后缀。若有“!”,则将包含偏移量的地址写回到Rn,若Rn是R15,则不能使用该后缀。后面所用时意义相同。
{}        表示括号内的内容是可选的。后面所用时意义相同。


      在上述指令中,若Rd为R15时,加载操作将会引起处理器转移到所写内容为地址的单元处,即使要进行加载操作,也不能使用后缀“B”或“T”。通常应避免对R15进行存储操作,若进行,则存储的值是当前指令的地址加一特定的常量。 


例如:
LDR        R8,[R10]                                    ;R8←[R10]
LDRNE  R2,[R5,#960]                     ;(有条件地)R2←[R5+960],R5←R5+960
LDR        R0,localdata                             ;加载一个字到R0寄存器,该字存 于localdata所指地址处
STR        R5,[R7],#-8!                          ;R5→[R7],R7←R7-8。先把[R7]放入R5,再修改R7,R7变了。相当于 i++
STRB     R0,[R3,-R8 ASR #2]              ;R0→[R3-R8/4],存储R0的最低有效字节,R3和R8不变 



        (2) LDR和STR —-半字和带符号字节:带符号的8位字节以及带符号和无符号的16位半字加载寄存器(LDR),对于存储寄存器(STR)指令是针对于16位半字的。对于带符号加载时是带符号扩展到32位,无符号加载时是用“0” 扩展到32位。

该组LDR和STR指令也都有以下4种句法形式:
Op {cond} type Rd,[Rn]         零偏移
op {cond} type Rd,[Rn,offset]{!}前索引偏移
Op {cond} type Rd,label       程序相对偏移
Op {cond} type Rd,[Rn],offset   后索引偏移


其中:type  必须是下面所列的形式之一:
SH        带符号半字(仅对LDR);
H           无符号半字
SB        带符号字节(仅对LDR)。
label    程序相对偏移表达式。偏移量必须是在当前指令的上下255字节范围内。
offset  加在Rn上的偏移量。其形式是下列两种之一:
① #expr  是取值范围为-255~+255的整数,经常是常量或常量表达式。
② {-} Rm   Rm是内含偏移量的寄存器,它不能是R15。 

例如:
LDRH     R1,[R0,#22]     ;R1←[R0+22],加载16位半字,0扩展到32位
LDREQSH  R11,[R6]        ;(有条件地)R11←[R6],加载16位半字,带符号扩展到32位
STRH     R4,[R0,R1]!   ;R4→[R0+R1],存储最低的有效半字到R0+R1所指的地址开始的两个字节处,地址写回R0
LDRSB    R6,constf           ;加载位于标号constf所指地址中的字节到R6中,带符号扩展 



        (3)LDR和STR —-双字:加载/存储两个相邻的寄存器,64位双字。

其句法有4种:
Op {cond} D Rd,[Rn]                            零偏移
Op {cond} D Rd,[Rn,offset] {!}         前索引偏移
Op {cond} D Rd,label                          程序相对偏移
Op {cond} D {T}  Rd,[Rn],offset       后索引偏移


其中:
Rd     加载/存储寄存器中的一个,另一个是R(d+1)。Rd必须是偶数寄存器,且不是R14
Rn      除非指令为零偏移,或不带写回的前索引,否则,Rn不允许与Rd和R(d+1)相同。
label  label必须是在当前指令的上下252字节范围内。

例如:
LDRD    R6,[R11]                  ;R6←[R11],R7←[R11+4]
STRD     R4,[R9,#24]         ;R4→[R9+24],R5→[R9+28]

 
 
        (4)LDM和STM:加载/存储多个寄存器,可以传送R0~R15的任意组合。
其句法如下:
op  {cond}  mode  Rn{!},reglist{^}

其中:mode是下列情况之一:
IA    每次传送后地址加1;
IB    每次传送前地址加1;
DA  每次传送后地址减1;
DB  每次传送前地址减1;
FD  满递减堆栈;
ED  空递减堆栈;
FA  满递增堆栈;
EA  空递增堆栈。
Rn不允许是R15。 reglist  所须加载/存储的寄存器列表,包含在括号中。多个寄存器间用逗号分开。
^     可选后缀。不允许在用户模式或系统模式下使用。它有以下两个功能:
①  若op是LDM且reglist中包含R15,那么除了正常的多寄存器传送外,还将SPSR也拷贝到CPSR中。这用于从异常处理返回,仅在异常模式下使用
②  数据传入或传出的是用户模式的寄存器,而不是当前模式的寄存器。相当于T。
 
例如:
STMFD   R13!,{R0,R4-R7,LR}    ;寄存器进栈。R13即SP由满栈递减。并修改SP指针。
LDMFD   R13!,{R0,R4-R7,LR}    ;寄存器出栈,从子程序返回。



        (5)SWP:在寄存器和存储器之间进行数据交换,其句法是:
SWP  {cond}  {B}  Rd,Rm,[Rn]
其中:B是可选后缀,若有B,则交换字节,否则交换字。
该指令作用是数据从存储器加载到Rd中,Rm中的内容存储到存储器,需交换数据存储单元的首地址在Rn中。在此,Rd和Rm可以相同,但Rn必须与Rd、Rm不同。 

[Rn]->Rd, Rm->[Rn],其中Rd和Rm可以相同也可以不同。
 
 
3.数据处理指令

    (1)ADD,SUB,RSB,ADC,SBC和RSC指令:加、减和反减指令,前三个不带进位或借位,后三个带进位或借位。
其句法是:
op  {cond}  {S}  Rd,Rn,Operand2

ADD指令用于将Rn和Operand2的值相加;
SUB指令用于从Rn的值中减去Operand2的值;
RSB指令用于从Operand2的值中减去Rn的值;

ADC指令用于将Rn和Operand2的值相加,再加上进位标志C的值;
SBC指令用于从Rn的值中减去Operand2的值,若进位标志C为0,结果再减1;
RSC指令用于从Operand2的值中减去Rn的值,若进位标志C为0,结果再减1。以上指令执行的结果均存于Rd中。  

其中:
S                      可选的后缀。若指定S,则根据操作结果更新条件码标志
Operand2      第二个操作数。后面所用时意义相同。它有以下两种可能的形式:
Rm{,shift}   符号的含义与前面一致。 
# immed_8r  取值为数字常量的表达式。常量必须对应8位位图(pattern)在32位字中被循环移位偶数位后的值。(??)

在使用这些指令时,应注意:
·若在这些指令后面加上后缀S,那么这些指令将根据其运算结果更新标志N,Z,C和V。
·若R15作为Rn使用,则使用的值是当前指令的地址加8。
·若R15作为Rd使用,则执行完指令后,程序将转移到结果对应的地址处。若此时指令还加有后缀S,则还会将当前模式的SPSR拷贝到CPSR。可以使用这一点从异常返回。
·在有寄存器控制移位的任何数据处理指令中,不能将R15作为Rd或任何操作数来使用。 


例如:
ADD    R3,R7,#1020                   ;immed_8r为1020,是0xFF循环右移30位
SUBS    R8,R6,#240                   ;R8←R6-240,运算完成后将根据结果更新标志
RSB   R4,R4,#1280                     ;R4←1280-R4
RSCLES  R0,R5,R0,LSL R4  ;有条件执行,执行完后更新标志 ,R4指定了R0被移位的位数。


    (2)AND,ORR,EOR和BIC指令
逻辑与、或、异或等指令。其句法是:
op {cond} {S} Rd,Rn,Operand2
其中所用到的符号意义与上述的相同。
AND,ORR和EOR指令分别完成按位将Rn和Operand2的值进行“与”、“或”和“异或”操作,结果存于Rd中。
BIC指令用于将Rn中的各位与Operand2的相应位的反码进行“与”操作,结果存于Rd中。 


使用这些指令时应注意:
若加有后缀S,这些指令执行完后将根据结果更新标志N和Z,在计算Operand2时更新标志C,不影响标志V。

例如:
AND      R9,R2,#0xFF00
ORREQ    R2,R0,R5
EORS     R0,R0,R3,ROR R6
BICNES   R8,R10,R0,RRX  

    (3)MOV和MVN指令
传送和传送非指令。其句法如下:
op {cond} {S}  Rd,Operand2
其中所用到的符号意义与上述的相同。
MOV指令将Operand2的值拷贝到Rd;MVN指令先将Operand2的值按位进行逻辑“非”操作,然后将结果拷贝到Rd。其对条件码的影响如同AND,ORR等指令。 


例如:
MOV      R5,R2
MVNNE   R11,#0xF000000B
MOVS     R0,R0,ASR R3 


    (4)CMP和CMN指令
比较和比较反值指令。其句法如下:
op  {cond}  Rn,Operand2
其中所用到的符号意义与上述的相同。
CMP指令从Rn的值中减去Operand2的值。除结果被舍弃外,其他与SUBS指令一样;CMN指令将Operand2的值加到Rn的值中,除结果被舍弃外,其他与ADDS指令一样。CMP和CMN指令执行后均根据结果更新标志N,Z,C和V。 
CMP:减。CMN:加。


例如:
CMP      R2,R9
CMN      R0,#6400
CMPGT   R13,R7,LSL #2 

    (5)TST和TEQ指令
测试和测试相等指令,其句法如下:
op  {cond}  Rn,Operand2
其中所用到的符号意义与上述的相同。
TST指令对Rn的值和Operand2的值进行按位“与”,除结果被舍弃外,其他与ANDS指令一样;TEQ指令对Rn的值和Operand2的值进行按位“异或”,除结果被舍弃外,其他与EORS指令一样。TST和TEQ指令执行后均根据结果更新标志N,Z,C和V。 

TST:与。TEQ:异或。

例如:
TST      R0,#0x3F8
TEQEQ   R10,R9
TSTNE   R1,R5,ASR R1 


    (6)MUL和MLA指令
乘法和乘加指令,其句法如下:
MUL  {cond}  {S}  Rd,Rm,Rs
MLA  {cond}  {S}  Rd,Rm,Rs,Rn
其中所用到的符号意义与上述的相同,但R15不能做Rd,Rm,Rs或Rn。Rd不能与Rm相同
MUL指令将Rm和Rs中的值相乘,并将最低有效的32结果放到Rd中;
MLA指令将Rm和Rs中的值相乘,再加上Rn的值,并将最低有效的32结果放到Rd中。
若带有后缀S,则这些指令将根据结果更新标志N和Z,而不影响标志V,标志C不确定。


例如:
MUL      R10,R2,R5
MLA      R10,R2,R1,R5
MULS     R0,R2,R2
MULLT    R2,R3,R2
MLAVCS  R8,R6,R3,R8 



4.分支指令

    (1)B和BL
分枝和带链接分枝指令,其句法如下:
op  {cond}  label
其中:label是程序相对偏移表达式。
B指令引起处理器转移到label对应的程序处;
BL指令将下一条指令的地址拷贝到R14(即链接寄存器LR)中,并引起处理器转移到label对应的程序处。 


例如:
B      loop1
BLE    ng+8
BL     loop2
BLLT    loop3 

    (2)BX
分枝并可选地交换指令集指令,其句法如下:
BX  {cond}  Rm
其中:Rm是含有转移地址的寄存器。Rm的位[0]不用来作为地址的一部分。若Rm的位[0]为1,则指令将CPSR中的标志T置位,且将目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则位[1]就不能为1。
BX指令将引起处理器转移到Rm中的内容所指向的地址处,若Rm的位[0]为1,则指令集变换到Thumb集。 

例如:
BX      R7
BXVS    R0


    (3)BLX
带链接分枝并可选地交换指令集,这条指令的句法结构有如下两种形式:
BLX  {cond}  Rm   带链接有条件转移到寄存器中的绝对地址;
BLX  label              带链接无条件转移到程序相对偏移地址;
其中:Rm是含有转移地址的寄存器。Rm的位[0]不用来作为地址的一部分。若Rm的位[0]为1,则指令将CPSR中的标志T置位,且将目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则位[1]就不能为1。 
BLX指令有如下用法:
·将下一条指令的地址拷贝到R14中;
·转移到label或Rm中的地址;
·若下面两条中的任何一条成立,则将指令集切换到Thumb。
① Rm的位[0]为1;
② 使用“BLX  label”指令形式。
例如:
BLX          R2
BLXNE    R0
BLX          Thumbsub 

 
5.协处理器指令

1)CDP
协处理器数据操作指令,其句法如下:
CDP  {cond}  coproc,opcode1,CRd,CRn,CRm{,opcode2}
其中:coproc  指令操作的协处理器名。标准名为pn,其中n为0~15;
opcode1    协处理器特定操作码;
CRd,CRn,CRm  协处理器寄存器;
opcode2     可选的协处理器特定操作码。 

(2) MCR和MCRR
将数据从ARM寄存器传送到协处理器,可指定各种附加操作,依据协处理器而定。其句法如下:
MCR  {cond}  coproc,opcode1,Rd,CRn,CRm{,opcode2}
MCRR  {cond}  coproc,opcode1,Rd,Rn,CRm
其中:Rd,Rn是ARM寄存器,为源寄存器,不允许是R15。 

(3) LDC和STC
在存储器和协处理器之间传送数据,其句法有以下三种形式:
Op {cond} {L} coproc,CRd,[Rn]          零偏移
Op {cond} {L} coproc,CRd,[Rn,#{-}offset]{!} 前索引偏移
Op {cond} {L}  coproc,CRd,[Rn],#{-}offset]  后索引偏移
其中:L为可选后缀,指明是长整数传送;其他符号如前所述。 

(4) MRC和MRRC
将数据从协处理器传送到ARM寄存器,可指定各种附加操作,依据协处理器而定。其句法如下:
MRC  {cond}  coproc,opcode1,Rd,CRn,CRm{,opcode2}
MRRC  {cond}  coproc,opcode1,Rd,Rn,CRm
其中:Rd,Rn是ARM寄存器,为目的寄存器,不允许是R15。 


6.杂项指令

(1) SWI
软件中断指令,其句法如下:
SWI  {cond}  immed_24
其中:immed_24为表达式,其值为0~224-1范围内的整数。
SWI指令引起SWI异常,使得处理器模式变换为管理模式,CPSR将被保存到管理模式的SPSR中,程序执行转移到SWI向量处。该指令不影响条件码标志。
例如:
SWI  0×123456 
 

(2) MRS
将CPSR或SPSR的内容传送到通用寄存器中,其句法如下:
MRS  {cond}  Rd,psr
其中:Rd不允许为R15;psr是CPSR或SPSR。
MRS和MSR配合使用,作为更新PSR寄存器的读—修改—写序列的一部分。该指令不影响条件码标志。
例如:
MRS      R3,SPSR 
 

(3) BKPT
设置断点指令,其句法如下:
BKPT  immed_16
其中:immed_16为表达式,其值为0~65536范围内的整数(16位整数)。
BKPT指令引起处理器进入调试模式。调试工具可以使用这一点在指令到达特定的地址时查询系统状态。
例如:
BKPT      0xF02C
BKPT      640 

 
7.ARM汇编程序规范 
 
        在只关心系统所具有功能的设计中,采用高级编程语言编写程序更合适,由于其隐藏了CPU执行指令的许多细节。但是,CPU执行指令的细节差异会反应在系统的非功能特性上,例如系统程序的规模和运行速度。因此,掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。 

ARM汇编程序中每一行的通用格式为:
        {标号} {指令|指示符|伪指令} {;注解}。
在ARM汇编语言源程序中,除了标号和注释外,指令、伪指令和指示符都必须有前导空格,而不能顶格书写。如果每一行的代码太长,可以使用字符“\”将其分行书写,并允许有空行。指令助记符、指示符和寄存器名既可以用大写字母,也可以用小写字母,但不能混用。注释从“;”开始,到该行结束为止。 

        标号代表一个地址,段内标号的地址值在汇编时确定,段外标号的地址值在链接时确定。在此要区别程序相对寻址和寄存器相对寻址。在程序段中,标号代表其所在位置与段首地址的偏移量,根据程序计数器PC和偏移量计算地址称为程序相对寻址。在映像中定义的标号代表标号到映像首地址的偏移量,映像的首地址通常被赋予一个寄存器,根据该寄存器值与偏移量计算地址称为寄存器相对寻址。 


符号定义指示符
符号定义指示符
 
数据定义指示符
数据定义指示符
 
报告指示符
报告指示符
 
汇编控制指示符
汇编控制指示符
 
杂项指示符
杂项指示符

 Leave a Reply

(必须填写)

(必须填写,邮件地址不会被泄露)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>