《ARM原理与C程序设计》课件第三章_第1页
《ARM原理与C程序设计》课件第三章_第2页
《ARM原理与C程序设计》课件第三章_第3页
《ARM原理与C程序设计》课件第三章_第4页
《ARM原理与C程序设计》课件第三章_第5页
已阅读5页,还剩174页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第三章ARM指令表3.1ARM指令学习程序框架3.2ARM指令格式3.3ARM指令寻址方式3.4ARM指令汇总本章小结3.1ARM指令学习程序框架

按照1.3.2小节中的方法,建立工程文件ex3_1.mcp,其中,源文件名为InstAn.s。在图1-16中,指定ROBase为0x30000000(对于UP-NETARM2410实验箱出厂设置)或者0x40000000(对于SBC2440出厂设置)。需要说明的是,如果用户更新了实验箱上的FLASH内容,则需要按照第五章的内容进行ARM汇编语言程序设计,即需要添加初始化S3C2410芯片的程序段。

InstAn.s的代码如下:

1

AREAInstAn,CODE,READONLY

2

ENTRY

3START

4

;<InstructionstobeAnalyzed>

5

;<ResultswillbeshowninRegisters>

6

;<EntertheRealViewDebuggerthenPress

Menu

“View|Registers”>

7;HereisanexamplewhichshowstheusageofMOV:

8MOVR0,#0x78

9MOVR2,R0

10STOP

11

BL STOP

12END上面的程序段中分号后面的为注释,START标号要顶格写,START标号后面书写需要分析的ARM指令,分析结果要在RealViewDebugger调试器的寄存器中查看(本书中不会出现printf等输出信息到控制台的语句,而很多与ARM相关的书里面都有类似的语句。本书程序的输出结果通过四种方式查看,即寄存器、存储器、显示屏等硬件输出设备或计算机串行终端显示)。上述程序演示了MOV指令的部分功能,其中,“MOVR0,#0x78”执行后,R0寄存器的值为0x78,“MOVR2,R0”执行后,寄存器R2的值为0x78。程序最后要有一个循环语句。3.2ARM指令格式

全部ARM指令的字长均为32位,按字对齐方式存储(一个字等于4个字节),如果第一条ARM指令的地址为0x00000000,则其下一条指令的地址为0x00000004,依次类推,即存储器中ARM指令的地址的最低两位总为0。

ARM指令的汇编语言语法格式为

<opcode>{<cond>}{S}<Rd>,<Rn>{,<shifter_operand>}

其中:<>为必需项,{}为可选项。

opcode表示ARM指令汇编语言助记符,如ADC、ADD等,针对ARM920T(即ARMv4T)而言,具体内容参见表3-1。表3-1基于ARMv4T架构的ARM指令助记符序号助记符序号助记符序号助记符序号助记符1ADC14LDR27MUL40STRH2ADD15LDRB28MVN41STRT3AND16LDRBT29ORR42SUB4B17LDRH30RSB43SWI5BIC18LDRSB31RSC44SWP6BL19LDRSH32SBC45SWPB7BX20LDRT33SMLAL46TEQ8CDP21MCR34SMULL47TST9CMN22MLA35STC48UMLAL10CMP23MOV36STM49UMULL11EOR24MRC37STR12LDC25MRS38STRB13LDM26MSR39STRBT

cond表示指令执行的条件码助记符。所有ARM指令都是条件执行的:当条件满足时,指令执行;当条件不满足时,指令不执行。条件码位于指令机器编码的高4位,如图3-1所示,即第31~28位,共有24=16种条件码,其含义和助记符如表3-2所示。

S表示如果指令中有S后缀,则指令执行将影响CPSR的值,否则不影响。

Rd表示目的寄存器。

Rn表示第一个源操作数寄存器。

shifter_operand表示第二个源操作数。图3-1ARM指令机器码汇总表3-2指令条件码助记符及其含义条件码[31:28]条件码助记符<cond>含义CPSR中条件标志位值0000EQ相等Z=10001NE不相等Z=00010CS/HS无符号数大于或等于C=10011CC/LO无符号数小于C=00100MI负数N=10101PL非负数N=00110VS上溢出V=10111VC未溢出V=01000HI无符号数大于C=1且Z=01001LS无符号数小于或等于C=0且Z=11010GE有符号数大于或等于(N=1且V=1)或(N=0且V=0),即N=V1011LT有符号数小于(N=1且V=0)或(N=0且V=1),即N≠V1100GT有符号数大于Z=0且N=V1101LE有符号数小于或等于Z=1且N≠V1110AL无条件执行-1111---

一般地,一条ARM汇编语言指令编译后对应于一条可执行的32位ARM机器码指令,ARM机器码指令如图3-1所示,其中第31~28位为条件码,从图3-1中可以分析出各操作数所占的位数及可能的取值范围。例如,Rn、Rd、Rs和Rm用于表示寄存器R0~R15中的某个,故均占有4位。

3.3ARM指令寻址方式

ARM指令寻址方式本质上是ARM汇编指令的编码规则,熟悉ARM指令寻址方式,有助于写出正确的ARM指令。在学习复杂的汇编语言指令集时,指令寻址方式显得尤为重要;尽管基于RISC指令集的ARM指令数量较少,但是了解ARM指令的寻址方式,可以更深入地掌握ARM汇编指令集。按照指令操作数类型,ARM指令集分为五种寻址方式,依次为数据处理操作数寻址、字与无符号字节存储/装入寻址、双字与半字及有符号字节存储/装入寻址、寄存器批量存储/装入寻址、协处理器存储/装入寻址。3.3.1数据处理操作数寻址

数据处理操作数寻址方式的指令语法为:

<opcode>{<cond>}{S}<Rd>,<Rn>,<shifter_operand>

其中,<shifter_operand>有11种形式,如下所述。

模式1:立即数

机器码:如图3-2所示。图3-2形式1的ARM指令编码语法:#<immediate>

这里,immediate为以图3-2中8位immed_8为低8位、高24位补0后的32位数循环右移2×rotate_imm位得到的立即数。因此,并非所有32位的数都能充当立即数,同时,规定当立即数小于0xFF时,immed_8=immediate,rotate_imm=0;当立即数大于0xFF时,选择使rotate_imm数值最小的编码形式。容易推算,0xFF1和0x102等是不合法的立即数,而0xFF0和0x104等则是合法的立即数。立即数0x3F0满足编码方式:

(1) immed_8=0x3F,rotate_imm=0xE;

(2) immed_8=0xFC,rotate_imm=0xF。此时,采用(1)方式编码,因为方式(1)下rotate_imm较小。如果在编程时写错了立即数,编译时会报错!

示例:MOVR0,#0x03

ADDR3,R3,#1

模式2:寄存器

机器码:如图3-3所示。图3-3形式2的ARM指令编码语法:<Rm>

这里,Rm为操作数的值;如果Rm或Rn指定为R15,则使用当前指令地址值加上8后的值。

示例:

ADDR3,R3,R0

ADDR3,R3,R15

;注:如果该指令地址为0x30000010,其运算为:

;

R3=R3+0x30000010+8

模式3:寄存器逻辑左移立即数

机器码:如图3-4所示。图3-4形式3的ARM指令编码语法:<Rm>,LSL#<shift_imm>这里,操作数等于Rm的值逻辑左移shift_imm位。如果Rm或Rn指定为15,则操作数使用当前指令地址值加上8后的值。示例:MOVR1,R0,LSL#2模式4:寄存器逻辑左移寄存器

机器码:如图3-5所示。图3-5形式4的ARM指令编码语法:<Rm>,LSL<Rs>这里,操作数为Rm的值逻辑左移Rs[7:0]位。因此,当Rs[7:0]大于等于32时,操作数将为0。R15不能用作Rn、Rd、Rs或Rm。示例:MOVR2,R0,LSLR1模式5:寄存器逻辑右移立即数

机器码:如图3-6所示。图3-6形式5的ARM指令编码语法:<Rm>,LSR#<shift_imm>这里,操作数为寄存器Rm的值右移shift_imm位。如果Rm或Rn指定R15,则操作数使用当前指令地址值加上8后的值。示例:MOVR2,R0,LSR#1模式6:寄存器逻辑右移寄存器

机器码:如图3-7所示。图3-7形式6的ARM指令编码语法:<Rm>,LSR<Rs>这里,操作数为Rm的值右移Rs[7:0]位。R15不能用作Rd、Rs、Rm或Rn。示例:MOVR2,R0,LSRR1模式7:寄存器算术右移立即数

机器码:如图3-8所示。图3-8形式7的ARM指令编码语法:<Rm>,ASR#<shift_imm>这里,操作数为Rm算术右移shift_imm位(要求:1≤shift_imm≤32),按Rm[31]进行符号扩展,即如果Rm[31]=0,则左边补0;如果Rm[31]=1,则左边补1。因此,当shift_imm=32时,操作数等于0(Rm[31]=0)或等于0xFFFFFFFF(Rm[31]=1)。如果Rm或Rn指定为R15,则操作数使用当前指令地址值加上8后的值。

示例:MOVR2,R1,ASR#4

模式8:寄存器算术右移寄存器

机器码:如图3-9所示。图3-9形式8的ARM指令编码语法:<Rm>,ASR<Rs>

这里,操作数为Rm的值算术右移Rs[7:0]位。当Rs[7:0]=0时,相当于不移位;当Rs[7:0]≥32时,操作数为00(Rm[31]=0)或等于0xFFFFFFFF(Rm[31]=1)。R15不能用作Rn、Rd、Rs或Rm。

示例:MOVR2,R1,ASRR0

模式9:寄存器循环右移立即数

机器码:如图3-10所示。图3-10形式9的ARM指令编码语法:<Rm>,ROR#<shift_imm>

这里,操作数循环右移shift_imm位(要求:1≤shift_imm≤31)。如果Rm或Rn指定为R15,则操作数使用当前指令地址值加上8后的值。

示例:MOVR2,R1,ROR#4

模式10:寄存器循环右移寄存器

机器码:如图3-11所示。图3-11形式10的ARM指令编码语法:<Rm>,ROR<Rs>

这里,操作数为Rm的值循环右移<Rs[4:0]>。R15不能用作Rn、Rd、Rs或Rm。

示例:MOVR2,R1,RORR0

模式11:寄存器扩展循环右移

机器码:如图3-12所示。图3-12形式11的ARM指令编码语法:<Rm>,RRX

这里,操作数为Rm的值逻辑右移一位(该位放入Shifter_

carry_out),CPSR的C标志位填充Rm的最高位空位。如果Rm或Rn指定R15,则操作数使用当前指令地址值加上8后的值。

示例:MOVR2,R1,RRX

备注:在上述移位操作中,无论是左移还是右移,最后移出的位的值均存放在Shifter_carry_out中。3.3.2字与无符号字节存储/装入寻址

字与无符号字节存储/装入寻址方式的指令语法为:

LDR | STR{<cond>}{B}{T}<Rd>,<addressing_mode>

其中,{<cond>}、{B}和{T}的位置可调换;<addressing_

mode>有9种模式(均适用于LDR、LDRB、STR和STRB;只有最后3种模式适用于LDRBT、LDRT、STRBT和STRT),如下所述。

模式1:立即数偏置

机器码:如图3-13所示。图3-13模式1的ARM指令编码语法:[<Rn>,#+/-<offset_12>]这里,操作数地址为Rn加上或减去12位的立即数值。U=1时为加;U=0时为减。B=0时为字操作;B=1时为无符号字节操作。L=0时为装入操作;L=1时为存储操作。R15为Rn时,使用当前指令地址加上8后的值。示例:

LDRR1,[R0,#0x04];将内存地址R0+0x4处的值装入R1中

LDRR1,[R15,#0x04];将内存地址PC+8+0x4处的值装入R1中

备注:要考虑小端或大端存储模式,例如:在小端模式下,对于字访问来说,地址0x30000000处的字是指0x30000003至0x30000000四个字节地址里的字节从高地址至低地址连接起来的32位字;地址0x30000001处的字也是指x30000003至0x30000000四个字节地址里的字节从高地址至低地址连接起来的字,只是最高字节处于0x30000000处,依次为0x30000003和0x30000002,最低字节地址为0x30000001。地址0x30000002处的字仍然是指x30000003至0x30000000四个字节地址里的字节连接起来的字,这时最高字节处于0x30000001地址处,依次为0x30000000和0x30000003,最低字节地址为0x30000002;同理,地址0x30000003处的字仍然是指x30000003至0x30000000四个字节地址里的字节连接起来的字,这时最高字节处于0x30000002地址处,依次为0x30000001和0x30000000,最低字节地址为0x30000003。大端模式下的排序模式正好相反。

尽管如上所述,作者建议,在进行字访问时,12位的立即数的最后两位应为0b00,即能被4整除。注意:STR表示的操作是向右赋值的。

模式2:寄存器偏置

机器码:如图3-14所示。图3-14模式2的ARM指令编码语法:[<Rn>,+/-Rm]这里,操作数地址为Rn(在此称为基址寄存器)的值加上或减去Rm(在此称为变址寄存器)的值。R15不能用作Rn。示例:LDRBR1,[R0,R2] ;将内存地址R0+R2处的字

节装入R1中

模式3:尺度寄存器偏置

机器码:如图3-15所示。图3-15模式3的ARM指令编码语法:有如下五种:

[<Rn>,+/-<Rm>,LSL#<shift_imm>]

[<Rn>,+/-<Rm>,LSR#<shift_imm>]

[<Rn>,+/-<Rm>,ASR#<shift_imm>]

[<Rn>,+/-<Rm>,ROR#<shift_imm>]

[<Rn>,+/-<Rm>,RRX]

这里,操作数地址为Rn加上或减去Rm的移位值。对于LSL,移位立即数shift_imm为0~31;对于LSR和ASR,shift_imm为1~32;对于ROR,shift_imm为1~31。R15不能用作Rm;R15用作Rn时,使用当前指令地址加上8后的值。

示例:LDRBR1,[R0,R2,LSL#1] ;将内存地址R0+R2<<1

处的字节值装入R1中

模式4:立即数预索引

机器码:如图3-16所示。图3-16模式4的ARM指令编码语法:[<Rn>,#+/-<offset_12]!这里,操作数地址为Rn的值加上或减去12位的立即数偏移量后的值,同时,这个值写入到Rn中。语法中的“!”号将设置机器码中的W位(即第21位),表示Rn加上或减去立即数后的值回赋给Rn。R15不能用作Rn。示例:LDRR1,[R0,#0x04]!模式5:寄存器预索引

机器码:如图3-17所示。图3-17模式5的ARM指令编码语法:[<Rn>,+/-<Rm>]!这里,操作数地址为Rn的值加上或减去Rm的值,这个地址值回赋给Rn。R15不能用作Rm和Rn。示例:LDRR1,[R0,R2]!;内存地址R0+R2处的值赋

;给R1,R0=R0+R2

模式6:尺度寄存器预索引

机器码:如图3-18所示。图3-18模式6的ARM指令编码语法:有如下五种:

[<Rn>,+/-<Rm>,LSL#<shift_imm>]!

[<Rn>,+/-<Rm>,LSR#<shift_imm>]!

[<Rn>,+/-<Rm>,ASR#<shift_imm>]!

[<Rn>,+/-<Rm>,ROR#<shift_imm>]!

[<Rn>,+/-<Rm>,RRX]!

该模式是在模式3操作的基础上,即操作数地址为Rn的值加上或减去Rm移位后的值,增加了写回操作,即地址值回赋给Rn。

示例:LDRBR1,[R0,R2,LSL#1]!

;内存地址R0+R2<<1处的值装入R1,

R0=R0+R2<<1

模式7:立即数后索引

机器码:如图3-19所示。图3-19模式7的ARM指令编码语法:[<Rn>],#+/-<offset_12>这里,操作数地址为Rn的值,如果指令条件满足,则Rn加上或减去12位立即数后的值赋给Rn。R15不能用作Rn。示例:LDRR1,[R0],#0x4;内存地址R0处的值赋给R1,R0=R0+4模式8:寄存器后索引

机器码:如图3-20所示。图3-20模式8的ARM指令编码语法:[<Rn>],+/-<Rm>这里,操作数地址为Rn的值,指令条件满足时,Rn加上或减去Rm的值赋给Rn。R15不能用作Rm和Rn。示例:LDRR1,[R0],R2;内存地址R0处的值赋给R1,R0=R0+R2模式9:尺度寄存器后索引

机器码:如图3-21所示。图3-21模式9的ARM指令编码语法:有如下五种:

[<Rn>],+/-<Rm>,LSL#<shift_imm>

[<Rn>],+/-<Rm>,LSR#<shift_imm>

[<Rn>],+/-<Rm>,ASR#<shift_imm>

[<Rn>],+/-<Rm>,ROR#<shift_imm>

[<Rn>],+/-<Rm>,RRX

这里操作数地址为Rn的值,Rn加上或减去Rm的移位值后的值赋给Rn。R15不能用作Rm或Rn。

示例:LDRR1,[R0],R2,LSL#0x01;内存地址R0处的值赋给R1,R0=R0+R2<<13.3.3双字与半字及有符号字节存储/装入寻址

双字与半字及有符号字节存储/装入寻址方式的指令语法为:

LDR | STR{<cond>}H | SH | SB | D<Rd>,

<addressing_mode>

其中,指令中H、SH、SB或D必有其一,条件<cond>可以放在指令助记符后面,例如,LDRHLS和LDRLSH均合法;<addressing_mode>有如下所述6种模式。

模式1:立即数偏置

机器码:如图3-22所示。图3-22模式1下的ARM指令编码语法:[<Rn>,#+/-<offset_8>]这里,操作数地址为Rn的值加上或减去8位立即数偏移量,其中,8位立即数的高四位为immedH,低四位为immedL。

STR开头的存储操作为自左向右,LDR开头的装入操作是自右向左的。图3-22至图3-27中,L、S和H的意义为:当LSH=0b001时为存储半字;当LSH=0b010时为装入双字;当LSH=0b011时为存储双字;当LSH=0b101时为装入无符号半字;当LSH=0b110时为装入有符号字节;当LSH=0b111时为装入有符号半字。R15用作Rn时,Rn为当前指令地址加上8的值。

注意:对于半字操作,建议立即数的最低位为0(实际上要求的是Rn加上或减去立即数的值的最低位为0),在小端存储模式下,返回的半字的高字节为操作数地址加1处的值,半字的低字节为该地址处的值;对于双字操作,细心的读者可能已经从表3-1中查证了,ARMv4T并不支持。如果编程时写了不支持的ARM指令,在RVDS中编译时,会提示“InstructionnotsupportedontargetCPU”(目标CPU不支持此指令)。

示例:

LDRHR1,[R0,#0x4] ;内存地址R0+4处的半字装入R1中

;实际上装入的是R0+5和R0+4两处

;的字节合并值

;要求:R0+4的最低位为0

模式2:寄存器偏置

机器码:如图3-23所示。图3-23模式2下的ARM指令编码语法:[<Rn>,+/-<Rm>]这里,操作数地址为Rn加上或减去Rm的值。R15不能用作Rm;R15用作Rn时,Rn的值取当前指令地址加上8。示例:LDRHR1,[R0,R2] ;内存地址R0+R2处的半字

;装入R1中模式3:立即数预索引

机器码:如图3-24所示。图3-24模式3下的ARM指令编码语法:[<Rn>,#+/-<offset_8>]!这里,操作数地址为Rn加上或减去8位立即数的值,同时,该操作数地址装入Rn中。8位立即数的高四位为immedH,低四位为immedL。示例:LDRHR1,[R0,#0x02]!;内存地址R0+0x02处的

;半字装入R1,R0=R0+2

模式4:寄存器预索引

机器码:如图3-25所示。图3-25模式4下的ARM指令编码语法:[<Rn>,+/-<Rm>]!

这里,操作数地址为Rn加上或减去Rm的值,同时,该操作数地址装入Rn中。

示例:LDRHR1,[R0,R2]!;内存地址R0+R2处的半字

;装入R1,R0=R0+R2

模式5:立即数后索引

机器码:如图3-26所示。图3-26模式5下的ARM指令编码语法:[<Rn>],#+/-<offset_8>

这里,操作数地址为Rn的值,当指令执行条件满足时,Rn加上或减去立即数offset_8的值赋给Rn。立即数offset_8的高四位为immedH,低四位为immedL。R15不能用作Rn。

示例:LDRHR1,[R0],#0x02;内存地址R0处的值装入

;R1,R0=R0+2

模式6:寄存器后索引

机器码:如图3-27所示。图3-27模式6下的ARM指令编码语法:[<Rn>],+/-<Rm>

这里,操作数地址为Rn的值,当指令条件满足时,Rn加上或减去Rm的值赋给Rn。图3-27中的SBZ(ShouldBeZero)为0。R15不能用作Rm或Rn。

示例:LDRHR1,[R0],R2 ;内存地址R0处的值装入R1,

;R0=R0+R23.3.4寄存器批量存储/装入寻址

寄存器批量存储/装入寻址方式的指令语法为:

LDM | STM{<cond>}<addressing_mode><Rn>{!},<registers>{^}

其中,<addressing_mode>有如下五种模式。

模式1:事后增加(IA=IncrementAfter)

机器码:如图3-28所示。图3-28模式1下的ARM指令编码语法:IA

图3-28至图3-31中,对于LDM指令,当PC位于register_list中时,S为1表示SPSR装入CPSR中;对于不使用PC的LDM指令和全部STM类指令,S为1表示使用用户模式下的寄存器组,而非当前模式下的寄存器。用户模式和系统模式下不能设置S位为1。W位表示操作完成后基址寄存器的值是否变化,如果W为1,则基址寄存器的值在操作完成后将增加或减少4乘以寄存器列表中包含的寄存器个数的值,是增加还是减少,视第23位的值而定,第23位(即U位)为1时增加,为0时减少。

L位为1时表示装入,为0时表示存储。16位长的寄存器列表register_list,每一位对应于一个寄存器,即第0位对应于R0,第1位对应于R1,依次类推,第15位对应于R15(即PC),列表中至少应包含一个寄存器,多个寄存器间用逗号分隔,连续的寄存器可以用“-”连接,如“R1-R4”表示“R1,R2,R3,R4”,列表用“{}”包括。可见,S是指指令语法中的“^”是否存在;W是指指令语法中的“!”是否存在;L是指指令语法中使用LDM还是STM。这里,定义操作数首地址start_address为基址寄存器Rn的值;操作数尾地址end_address为Rn与4乘以寄存器列表中寄存器个数的和,再减去4的差,即

start_address=Rn,end_address=Rn+4

×(register_list各位中置1的个数)–4

如果是LDM操作,操作是自左向右的(与LDR等相反),即首地址至尾地址各个字地址内的值对应装入寄存器列表中;如果是STM操作,操作是自右向左的(与STR等相反),即寄存器列表中各个寄存器的值存入自首地址至尾地址相对应的地址处。如果指令中使用“!”,则尾地址end_address加上4的值赋给Rn,即

Rn=Rn+4×(register_list各位中置1的个数)

示例:

STMIAR0,{R1-R4};[0]赋给R1,[R0+4]赋给R2,[R0+8]

;赋给R3,[R0+12]赋给R4

STMIAR0!,{R1-R4}; [R0]赋给R1,[R0+4]赋给R2,

;[R0+8]赋给R3,[R0+12]赋给R4,

;R0=R0+16

说明:细心的读者调试指令时可能会发现,上述两个指令中,不带有“IA”结果是一样的,例如,第一条指令等同于STMR0,{R1-R4},道理是显然的。模式2:预先增加(IB=IncrementBefore)

机器码:如图3-29所示。图3-29模式2下的ARM指令编码语法:IB这里,首地址为start_address=Rn+4,尾地址为end_address=Rn+4×(register_list各位中置1的个数),当指令中出现“!”时,Rn=Rn+4×(register_list各位中置1的个数)。示例:

STMIBR0,{R1-R3} ; [R0+4]赋给R1,[R0+8]赋给R2,

;[R0+12]赋给R3

STMIBR0!,{R1-R3} ; [R0+4]赋给R1,[R0+8]赋给R2,

;[R0+12]赋给R3,R0=R0+12

模式3:事后减少(DA=DecrementAfter)

机器码:如图3-30所示。图3-30模式3下的ARM指令编码语法:DA

这里,首地址为start_address=Rn-4×(register_list各位中置1的个数)+4,尾地址为end_address=Rn,当指令中出现“!”时,Rn=Rn-4×(register_list各位中置1的个数)。

示例:

STMDAR0,{R1-R3};[R0-8]赋给R1,[R0-4]赋给R2,

;[R0]赋给R3

STMDAR0!,{R1-R3};[R0-8]赋给R1,[R0-4]赋给R2,

;[R0]赋给R3,R0=R0–12

模式4:预先减少(DB=DecrementBefore)

机器码:如图3-31所示。图3-31模式4下的ARM指令编码语法:DB这里,首地址为start_address=Rn-4×(register_list各位中置1的个数),尾地址为end_address=Rn-4,当指令中出现“!”时,Rn=Rn-4×(register_list各位中置1的个数)。示例:

STMDBR0,{R1-R3} ;[R0-12]赋给R1,[R0-8]赋给R2,

;[R0-4]赋给R3

STMDBR0!,{R1-R3};[R0-12]赋给R1,[R0-8]赋给R2,;[R0-4]赋给R3,R0=R0-12模式5:堆栈操作

堆栈可用于保存寄存器的值,通过压栈(或称入栈)将寄存器的值压入栈中保存,通过出栈操作恢复寄存器中的数值。尽管堆栈本质上是一段连续的内存空间,但是,有其专用的堆栈操作,根据堆栈指令位置及其移动方向,分为四种方式:即FD、ED、FA和EA。其中,F表示Fullstacks,即堆栈指针位置指向栈顶数据(如果有压栈操作,堆栈指针必须首先移动到栈顶前面的一个字空间,因此压栈(STM)时,F相当于Before;如果有出栈操作,由于堆栈指针指向栈顶数据,只需直接取数据即可,因此,出栈(LDM)时,F相当于After)。

E表示Emptystacks,即堆栈指针位置指向栈顶数据前面的一个地址空间,如果有一个压栈操作,该地址空间将保存数据而成为栈顶数据(同样道理,压栈(STM)时,E相当于After;出栈(LDM)时,E相当于Before)。F和E表示堆栈指针位置,而D和A表示堆栈指针移动方向。D为Descendingstacks,即堆栈指针移动方向为内存地址减少的方向。A为Ascendingstacks,表示堆栈指针移动方向为内存地址增大的方向。因此,有类似的8种操作,即LDMFA、LDMFD、LDMEA、LDMED和STMFA、STMFD、STMEA、STMED,对应于机器码中L(第20位)、P(第24位)、U(第23位)的值依次为:0b100、0b101、0b110、0b111和0b011、0b0b0、0b001、0b000。出于协处理对堆栈访问的支持,建议使用FD或EA方式。

示例程序StackOp.s

1 AREAINIT,CODE,READONLY

2 ENTRY

3START

4 MOV R2,#0x12 ;(1)

5 MOV R3,#0x55 ;(2)

6 MOV R4,#0xAA ;(3)

7

8 MOV R0,#0x30000000 ;(4)

9 MOV R1,#0x800 ;(5)

10 ADD R0,R0,R1 ;(6)

11 MOV SP,R0

;(7)

12

13 STMFD SP!,{R2,R3,R4} ;(8)

14 MOV R4,#0x88 ;(9)

15

16 LDMFD SP!,{R2-R4} ;(10)

17STOP

18 BL STOP

19 END

程序中各标号的解释如下:

(1) R2=0x12;

(2) R3=0x55;

(3) R4=0xAA;

(4) R0=0x30000000;

(5) R1=0x800;

(6) R0=R0+R1=0x30000800;

(7) SP=0x30000800;

(8) [0x300007F4]=0x12,[0x300007F8]=0x55,[0x3000

07FC]=0xAA,

SP=0x300007F4;

(9) R4=0x88;

(10) R2=0x12,R3=0x55,R4=0xAA,SP=0x30000800。

请注意SP的值的变化情况。3.3.5协处理器存储/装入寻址

这里讨论协处理器存储/装入寻址方式的编码和语法,第3.4节中将针对ARM920T微处理器具体讨论协处理器指令(约5个)的应用及示例。

协处理器存储/装入寻址方式的指令语法为:

<opcode>{<cond>}{L}<coproc>,<CRd>,

<addressing_mode>

其中,<addressing_mode>有下述四种模式。

模式1:立即数偏置

机器码:如图3-32所示。图3-32模式1下的ARM指令编码语法:[<Rn>,#+/-<offset_8>*4]图3-32至图3-35中,U=1表示加;U=0表示减。N位是协处理器无关的标识位,用于区分不同长度的传递值。W位(第21位)表示指令中有无“!”,W=1表示内存地址写回寄存器,W=0则不写回。L=1表示装入,L=0表示存储。如果指令执行条件满足,那么首地址start_address=Rn+/-offset_8×4(U=1时取加号,U=0时取减号),尾地址end_address=start_address+4×(协处理器的数目cp_num)。

R15用作Rn时,Rn的值为当前指令地址加上8。

模式2:立即数预索引

机器码:如图3-33所示。图3-33模式2下的ARM指令编码语法:[<Rn>,#+/-<offset_8>*4]!

如果指令执行条件满足,那么首地址start_address=Rn+/-offset_8×4(U=1时取加号,U=0时取减号),尾地址end_address=start_address+4×(协处理器的数目cp_num)。首地址赋给Rn。

R15不能用作Rn。

模式3:立即数后索引

机器码:如图3-34所示。图3-34模式3下的ARM指令编码语法:[<Rn>],#+/-<offset_8>*4

如果指令执行条件满足,那么首地址start_address=Rn,尾地址end_address=start_address+4×(协处理器的数目cp_num)。Rn=Rn+/-offset_8×4(U=1时取加号U=0时取减号)。

R15不能用作Rn。

模式4:无索引

机器码:如图3.35所示。图3-35模式4下的ARM指令编码语法:[<Rn>],<option>如果指令执行条件满足,那么首地址start_address=Rn,尾地址end_address=start_address+4×(协处理器的数目cp_num)。<option>指定协处理器额外的指令参数,取值为0~255的整数,用“{}”包括。

R15用作Rn时,Rn的值为当前指令地址加上8。

3.4ARM指令汇总

ARMv6指令集版本具有114条ARM指令,但是ARMv4T仅支持其中的49条指令,如表3-1所示。出于节省篇幅和增强针对性,这里仅介绍表3-1所示的ARM指令(当然,记忆指令是需要时间和方法的),将这些指令分为九类,即赋值指令2条、算术运算指令12条、跳转指令3条、比较指令2条、逻辑运算指令6条、CPSR访问指令2条、内存访问指令16条、软件中断指令1条以及协处理器指令5条,共计49条。此外,本节还将介绍4条ARM伪指令。3.4.1赋值指令

赋值指令有2条,即MOV和MVN,如下所述。

MOV指令(赋值)

语法:MOV{<cond>}{S}<Rd>,<Oprand2>

解释:

cond表示指令执行条件,如表3-2所示,只有满足条件时指令才能被执行。如果cond被忽略,则表示使用了条件码AL,即该指令总被执行。

S出现在指令中时,将设置指令的S位(第20位)为1,表示指令的执行将影响和刷新CPSR寄存器的某些位。

Rd寄存器为目的操作数。

Oprand2为第二个操作数,可以为立即数(是8位整数左边扩展24个0后的32位数循环右移32以内的偶数位得到的)、寄存器、寄存器移位立即数和寄存器移位寄存器。移位方式有逻辑左移(LSL)、逻辑右移(LSR)、算术右移(ASR)、循环右移(ROR)、带扩展位的循环右移(RRX)。

用“{}”括起来的为可选项,用“<>”括起来的为必选项。

操作:

如果执行条件满足,那么

Rd=Oprand2如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=最后移出的位(注意:这种说法稍欠准确)

V不受影响用途:

将某个特定值的立即数装入寄存器;将一个寄存器的值赋给另一个寄存器;移位操作;左移n位实现操作数乘以2n的运算;指令“MOVPC,LR”可以实现跳转;当PC为目的操作数,且S出现在指令中时,例如,“MOVSPC,LR”执行跳转的同时,还将SPSR的值赋给CPSR。

示例:

MOVR1,#0x01 ; R1=0x1

MOVR2,R1

; R2=R1=0x1

MOVR3,R2,LSL#0x2 ; R3=R2<<2=4

MOVR4,R3,LSRR1 ; R4=R3>>R1=2

MVN指令(取反赋值)

语法:MVN{<cond>}{S}<Rd>,<Oprand2>

解释:略

操作:

如果执行条件满足,那么

Rd=Oprand2的取反

如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=最后移出的位

V不受影响

用途:

用作某些位的屏蔽;计算一个数值的二进制补码。

示例:

MVNR4,R3,LSRR1;R4=~(R3>>R1)3.4.2算术运算指令

算术运算指令有12条,即ADD、ADC、MLA、MUL、RSB、RSC、SBC、SMLAL、SMULL、SUB、UMLAL以及UMULL,如下所述。

ADD指令(加法)

语法:ADD{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:

Rd寄存器为目的操作数。

Rn寄存器为第一个源操作数。

Oprand2为第二个源操作数,可以为立即数(是8位整数左边扩展24个0后的32位数循环右移32以内的偶数位得到的)、寄存器、寄存器移位立即数和寄存器移位寄存器。移位方式有逻辑左移(LSL)、逻辑右移(LSR)、算术右移(ASR)、循环右移(ROR)、带扩展位的循环右移(RRX)。

操作:

如果执行条件满足,那么

Rd=Rn+Oprand2

如果S=1且Rd=R15,那么如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的进位

V=结果的溢出位用途:

实现两个数值的加法运算;使用形如“ADDRx,Rx,#1”实现累加运算;使用形如“ADDRd,Rx,Rx,LSL#n”实现Rx的(2n+1)倍运算;使用形如“ADDRd,PC,#offset”获得一个基于PC的相对地址(此处,PC的值为当前指令地址加上8)。

示例:

ADDR2,R1,#2;R2=R1+2

ADDR3,R1,R2;R3=R1+R2

ADDR4,R4,R3,LSL#1;R4=R4+R3<<1

ADC指令(带进位加法)

语法:ADC{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:略

操作:

如果执行条件满足,那么

Rd=Rn+Oprand2+CPSR的C标志位

如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的进位

V=结果的溢出位

用途:

在实现64位的加法操作时,ADC用于两个加数的高32位数相加,例如,R1和R0以及R3和R2存入两个64位数,其中,R0和R2存放低32位,R1和R3存放高32位,这两个64位数相加的结果存放在R5和R4中,其中,R4存放结果的低32位,R5存放结果的高32位,则指令为

ADDSR4,R0,R2;注意,ADDS要带有S

ADCR5,R1,R3;如果使用ADCS,则结果影响CPSR

此外,可以用例如“ADCSR0,R0,R0”实现带扩展位的逐位循环移位操作。

示例:略

SUB指令(减法)

语法:SUB{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:略

操作:

如果执行条件满足,那么

Rd=Rn-Oprand2如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的借位取反

V=结果的溢出位(这里是指被减数小于减数的情况)用途:

实现数值的减1操作,形如“SUBRi,Ri,#1”;SUBS由于影响CPSR,在循环控制中经常被用到;SUBS也常用于中断(或异常)返回中,形如“SUBSPC,R15,#4”。

示例:略

SBC指令(带借位减法)

语法:SBC{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:略

操作:

如果执行条件满足,那么

Rd=Rn-Oprand2–NOT(C标志位)

如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的借位取反

V=结果的溢出位用途:

用于实现两个64位数的减法,如果寄存器对R1、R0和R3、R2存放64位数,其中R0和R2存放低32位,R1和R3存放高32位,运算结果存入R5、R4中(R4存放低32位,R5存放高32位),则指令为:

SUBSR4,R0,R2

SBCR5,R1,R3

示例:略

RSB指令(逆向减法)

语法:RSB{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:略

操作:如果执行条件满足,那么

Rd=Oprand2-Rn

如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的借位取反

V=结果的溢出位用途:

产生负数(二进制补码表示),指令形如“RSBRd,Rx,#0”;产生一个数的2n–1倍,指令形式如“RSBRd,Rx,Rx,LSL#n”。

示例:略

RSC指令(带借位逆向减法)

语法:RSC{<cond>}{S}<Rd>,<Rn>,<Oprand2>

解释:略

操作:

如果执行条件满足,那么

Rd=Oprand2–Rn–NOT(C标志位)如果S=1且Rd=R15,那么

如果当前工作模式有SPSR,那么

CPSR=SPSR

否则,执行结果不可预见

如果S=1但Rd≠R15,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C=结果的借位取反

V=结果的溢出位用途:

用于实现64位的减法运算,例如,0减去一个64位的数,存放在R1、R0中(R0存放32位,R1存放高32位),结果存放在R3、R2中(R2存放低32位,R3存放高32位),指令如下:

RSBSR2,R0,#0

RSBR3,R1,#0

示例:略

MUL指令(乘法)

语法:MUL{<cond>}{S}<Rd>,<Rm>,<Rs>

解释:

Rd寄存器为目的操作数,存放乘积。

Rm寄存器为第一个源操作数,存放被乘数。

Rs寄存器为第二个源操作数,存放乘数。

操作:

如果执行条件满足,那么

Rd=(Rm*Rs)[31:0]

如果S=1,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C无意义或不受影响

V不受影响用途:

实现两个数的乘法操作,由于乘积结果取低32位,因此,对于无符号数和有符号数来说,结果是一样的。这个指令多用于乘积结果不超过32位的乘法操作,实际中要慎用!

示例:

MULR3,R2,R1;R3=R2*R1结果的低32位

MLA指令(乘加)

语法:MLA{<cond>}{S}<Rd>,<Rm>,<Rs>,<Rn>

解释:

Rn寄存器为第三个源操作数,存储的值被加到Rm*Rs的积上。操作:

如果执行条件满足,那么

Rd=(Rm*Rs+Rn)[31:0]

如果S=1,那么

CPSR的标志位赋值如下:

N=Rd[31]

Z=1(Rd为0)或0(Rd不为0)

C无意义或不受影响

V不受影响用途:

实现32位数的乘加运算,Rd不能与Rm相同(ARMv6除外),由于乘法运算和加法运算结果均取低32位,所以,该指令主要用于结果不超过32位的乘加操作,实际中要慎用!

示例:略

SMULL指令(32位有符号乘法)

语法:SMULL{<cond>}{S}<RdLo>,<RdHi>,<Rm>,<Rs>

解释:

RdLo寄存器为第一个目的操作数,存储乘积的低32位。

RdHi寄存器为第二个目的操作数,存储乘积的高32位。操作:

如果执行条件满足,那么

RdHi=(Rm*Rs)[63:32]

RdLo=(Rm*Rs)[31:0]

如果S=1,那么

CPSR的标志位赋值如下:

N=RdHi[31]

Z=1(RdHi和RdLo均为0)或0(RdHi或RdLo不为0)

C不受影响

V不受影响用途:

该指令是真正意义下的乘法指令。不能使用R15,RdHi和RdLo不能相同。

示例:略

SMLAL指令(32位有符号乘加)

语法:SMLAL{<cond>}{S}<RdLo>,<RdHi>,<Rm>,<Rs>

解释:略

操作:

如果执行条件满足,那么

RdLo=(Rm*Rs)[31:0]+RdLo(原先的值)

RdHi=(Rm*Rs)[63:32]+RdHi+“(Rm*Rs)[31:0]+RdLo(原先的值)”的进位

如果S=1,那么

CPSR的标志位赋值如下:

N=RdHi[31]

Z=1(RdHi和RdLo均为0)或0(RdHi或RdLo不为0)

C不受影响

V不受影响

用途:

该指令是真正意义上的乘加运算。不用使用R15,RdHi和RdLo不能相同。

示例:略

UMULL指令(无符号32位乘法指令)

语法:UMULL{<cond>}{S}<RdLo>,<RdHi>,<Rm>,<Rs>

解释:略

操作:

如果执行条件满足,那么

RdHi=(Rm*Rs)[63:32];无符号数

RdLo=(Rm*Rs)[31:0]

如果S=1,那么

CPSR的标志位赋值如下:

N=RdHi[31]

Z=1(RdHi和RdLo均为0)或0(RdHi或RdLo不为0)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论