版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第3章ARM指令集与编程主要内容3.1总体介绍:指令分类,特点,格式,条件码3.2ARM指令寻址方式3.3数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令(略),前导零计数(略)3.4程序状态访问指令3.5跳转指令3.6单数据访存指令3.7多数据访存指令3.8其它指令:信号量操作指令,异常中断产生指令,协处理器指令(略)3.9伪指令3.10Thumb指令集3.1总体介绍:
指令分类,特点,格式,条件码3.1.1指令分类
ARM指令集总体分为6类指令数据处理指令:数据传输指令,算术指令,逻辑指令,比较指令,乘法指令,前导零计数。程序状态访问指令:mrs和msr。跳转指令:b和bl。访存指令(Load/Store):单数据访存指令,多数据访存指令,信号量操作指令。异常中断产生指令:swi和bkpt。协处理器指令。3.1.2指令特点所有指令都是32bit。大多数指令都在单周期内完成。所有指令都可以条件执行。load/store体系结构。指令集可以通过协处理器扩展3.1.3ARM指令的格式<Opcode>{<cond>}{s}<Rd>,<Rn>,<Operand2>Cond:指令的条件码。Opcode:指令操作码。S:操作是否影响cpsr。Rn:包含第一个操作数的寄存器编码。Rd:目标寄存器编码。Operand2:第2操作数。Cond001OpcodeSRnRdOperand20111215161920212425272831783.1.4ARM指令的条件执行所有的ARM指令可包含一个可选的条件码,只有在cpsr中的条件标志位满足指定的条件时,指令才会被执行。不符合条件的代码依然占用一个时钟周期(相当于一个NOP指令)。//r0,r1,r2,r3,r4:a,b,c,d,ecmp r0,r1cmpeq r2,r3addeq r4,r4,#1if((a==b)&&(c==d)){ e++;}(1)ARM指令的条件域EQ/NE:等于/不等于(equal/notequal)HS/LO:无符号数高于或等于/无符号数小于(higherorsame/lower)HI/LS:无符号数高于/无符号数低于或等于(higher/lowerorsame)GE/LT:有符号数大于或等于/有符号数小于(greaterorequal/lessthan)GT/LE:有符号数大于/有符号数小于或等于(greaterthan/lessorequal)MI/PL:负/非负VS/VC:溢出/不溢出(overflowset/overflowclear)CS/CC:进位/无进位(carryset/carryclear)(2)ARM指令的条件码0000EQZ置位相等/等于00001NEZ清0不等0010CS/HSC置位进位/无符号高于或等于0011CC/LOC清0无进位/无符号低于0100MIN置位负数0101PLN清0非负数0110VSV置位溢出0111VCV清0无溢出(2)ARM指令的条件码(续)1000HIC置位且Z清0无符号高于1001LSC清0或Z置位无符号低于或等于1010GEN等于V有符号大于或等于1011LTN不等于V有符号小于1100GTZ清0且N等于V有符号大于1101LEZ置位或N不等于V有符号小于或等于1110AL任何状态总是(always)1111NV无从不(never)注:AL是默认的,NV不建议使用。3.2ARM指令寻址方式3.2.1立即数方式指令中在操作码字段后面的地址码部分不是通常意义上的操作数地址,而是操作数本身。ADDR3,R3,#1;R3=R3+1ANDR8,R7,#0xff;R8=R7[7:0]
第2个源操作数为一个立即数,以“#”为前缀,十六进制值以在“#”后加“0x”或“&”表示。3.2.2寄存器寻址ADDR0,R1,R2;R0=R1+R2
这条指令将两个寄存器(R1和R2)的内容相加,结果放入第3个寄存器R0中。必须注意写操作数的顺序,第1个是结果(目标)寄存器,然后是第一操作数寄存器,最后是第二操作数寄存器。3.2.3寄存器移位寻址这种寻址方式是ARM指令集特有的。第2个寄存器操作数在与第1个操作数结合之前,选择进行移位操作。<Rm>,LSL#<shift_imm>;<Rm>,LSL<Rs>;ADDR3,R2,R1,LSL#3;R3=R2+8×R1寄存器R1的内容逻辑左移3位,再与寄存器R2内容相加,结果放入R3中。逻辑移位
LSL:逻辑左移(LogicalShiftLeft)。寄存器中字的低端空出的位补0。·LSR:逻辑右移(LogicalShiftRight)。寄存器中字的高端空出的位补0。·ASR:算术右移(ArithmeticShiftRight)。算术移位的对象是带符号数,在移位过程中必须保持操作数的符号不变。若源操作数为正数,则字的高端空出的位补0。若源操作数为负数,则字的高端空出的位补1。·ROR:循环右移(RotateRight)。从字的最低端移出的位填入字的高端空出的位。·RRX:扩展为1的循环右移(RotateRightExtendedby1place)。操作数右移一位,空位(位[31])用原C标志填充。移位操作过程在任何数据处理指令中,第二寄存器操作数可以有应用该操作数的移位操作.逻辑移位LSL:逻辑左移字的最小位空位清零LSR:逻辑右移字的最大位空位清零.移位操作算术移位:ASR,正数的ASR=LSR循环移位:ROR,RRX移位操作指令中的地址码给出某一通用寄存器的编号。在被指定的寄存器中存放操作数的有效地址,而操作数则存放在存储单元中,即寄存器为地址指针。针对Load/Store指令。LDRR0,[R1];R0=[R1]STRR0,[R1];[R1]=R0
寄存器间接寻址使用一个寄存器(基址寄存器)的值作为存储器的地址。3.2.4寄存器间接寻址Cond01IPU0W1RnRdAddress_mode3128272625242322212019161512110Cond0101UB0LRnRdOffset_123128272625242322212019161512110Cond0101UB0LRnRd00000000Rm3128272625242322212019161512110Cond0101UB0LRnRdShift_immshift0Rm3128272625242322212019161512110343467LDR指令的基本格式[<Rn>,#+/-<offset_12>][<Rn>,+/-<Rm>][<Rn>,+/-<Rm>,<shift>#<shift_imm>]3.2.5变址寻址变址寻址就是将基址寄存器的内容与指令中给出的位移量相加,形成操作数有效地址。变址寻址用于访问基址附近的存储单元,包括:
基址加偏移[<Rn>,#+/-<offset_12>]基址加索引寻址[<Rn>,+/-<Rm>]寄存器间接寻址是偏移量为0的基址加偏移寻址。基址加偏移寻址中的基址寄存器包含地址,需加(或减)(最大4KB)的偏移来计算访问的地址。LDRR0,[R1,#4];R0=[R1+4]这是前索引寻址方式。带自动索引的前索引寻址。LDRR0,[R1,#4]!;R0=[R1+4];R1=R1+4“!”符号表明指令在完成数据传送后应该更新基址寄存器后索引寻址。基址不带偏移作为传送的地址,传送后自动索引。
LDRR0,[R1],#4;R0=[R1];R1=R1+4基址加索引寻址有时指令指定一个基址寄存器,再指定另一个寄存器(索引),其值作为偏移加到基址上形成存储器地址。例如指令:
LDRR0,[R1,R2];R0=[R1+R2]3.2.6块拷贝寻址
ARM支持两种不同角度的块寻址机制,两者都映射到相同的基本指令——多寄存器传送指令。多寄存器传送指令可以用于把一块数据从存储器的某一位置拷贝到另一位置;基于数据是存储在基址寄存器的地址之上还是之下,地址是在存储第1个值之前还是之后增加还是减少。
下图说明了4种不同情况的多字节传送指令传送前后的内存变化,以及使用自动寻址时如何修改基址寄存器。指令执行前的基寄存器是R9,指令执行后的基寄存器是R9’。STMIAR9!,{R0,R1,R5}STMIBR9!,{R0,R1,R5}STMDAR9!,{R0,R1,R5}STMDBR9!,{R0,R1,R5}3.2.7堆栈寻址堆栈是一种按特定顺序进行存取的存储区。“后进先出”(LIFO)。栈指针所指定的存储单元就是堆栈的栈顶。存储器堆栈可分为两种:向上生长:即向高地址方向生长,称为递增堆栈(ascendingstack)。向下生长:即向低地址方向生长,称为递减堆栈(descendingstack)。堆栈指针指向最后压入堆栈的有效数据项,称为满堆栈(fullstack)。堆栈指针指向下一个数据项放入的空位置,称为空堆栈(emptystack)。
ARM对堆栈的使用一般用多寄存器传送指令,是一种有效的保存处理器状态和多字节传送的有效方式。ARM硬件中的堆栈分为以下四种类型:①满向上生长型(FA):堆栈按高地址方向生长,当前堆栈指针指向最高有效值;②空向上生长型(EA):堆栈按高地址方向生长,当前堆栈指针指向第一个空值;③满向下生长型(FD):堆栈按低地址方向生长,当前堆栈指针指向最低有效值;④空向下生长型(ED):堆栈按低地址方向生长,当前堆栈指针指向第一个空值。
若R3~R9保存的是有用的值,就应该把它们压进堆栈进行保存。即STMFDR13!,{R3-R9};
存储寄存器到堆栈。。。。。。LDMFDR13!,{R3-R9};
从堆栈恢复其中第一条和最后一条指令的“FD”表明是满递减堆栈寻址方式。
堆栈和块拷贝角度的多寄存器加载和存储指令映射堆栈用一般数据存取L位存取P位前变址/后变址U位加/减空向下生长型(之前增量)LDMEDLDMIB111满向下生长型(之后增量)LDMFDLDMIA101空向上生长型(之前增量)LDMEALDMDB110满向上生长型(之后增量)LDMFALDMDA100满向上生长型(之前增量)STMFASTMIB011空向上生长型(之后增量)STMEASTMIA001空向下生长型(之前增量)STMFDSTMDB010满向下生长型(之后增量)STMEDSTMDA0003.2.8相对寻址相对寻址是变址寻址的一种变通,由程序计数器PC提供基地址。指令中的地址码字段作为位移量。BLSUBR;转移到SUBR……;返回到此……SUBR…;子程序入口地址MOVPC,R14;返回3.3ARM数据处理指令3.3数据处理指令数据传输指令:mov和mvn算数指令:add、adc、sub、sbc,rsb和rsc逻辑指令:and、orr、eor和bic比较指令:cmp、cmn、tst和teq3.3.1数据处理指令的特点所有的操作数要么来自寄存器,要么来自立即数,不会来自内存。如果有结果,则结果一定是为32位宽,并且放在一个寄存器中,不会写入内存。(有一个例外:长乘法指令产生64位结果)每一个操作数寄存器和结果寄存器都在指令中独立指出,即:ARM指令采用3地址模式:<Operation>Rd,Rn,Rm3.3.2四种寻址方式和s后缀addr0,r1,r2addr0,r1,#0xffaddr0,r1,r1,LSLr2CondSRnRd第2操作数078111215161920opcode212400X25272831#immed_8#rot0781100000000Rm03411方式1:#immed方式2:Rm0000Rm03411Rs78方式3:RmLSLRsshiftRm03411#immed_567方式4:RmLSL#immed_5(#immed_5取值范围0-31)addr0,r1,r1,LSL#31(1)四种寻址方式的硬件支持寄存器,可能需要移位。如需移位,移位值可为:5bit的无符号整数(0-31)在指令的最低字节指定的另一寄存器立即数
8比特数8比特数循环右移偶数位右移位数由汇编器自动计算(2)立即数方式ARM指令中的立即数,由一个8bit的常数循环右移偶数位得到:立即数=(0->255)循环右移
2N位例子:合法立即数:0x3fc,0x0,0xf0000000,0xf0000001非法立即数:0x1fe,0xffff,0x1010,0xf0000010(2)立即数方式(续)同一个立即数可能有多个表示方法。如:0x3f0=0x3f循环右移28位0x3f0=0xfc循环右移30位对立即数的编码规则:如果立即数在0–0xff之间,移位数为0。否则,就取决于编译器了。指令“movr0,#0x3f0”在ADS1.2中被编译为0xe3a00ffc,在arm-elf-gcc-2.95.3中被编译为0xe3a00e3f。(2)立即数方式(续)对于有互补操作的指令,编译器可以做智能的转换,比如:mvnr1,0xffffff00 -> movr1,0xffaddr1,r1,#0xffffff00 -> subr1,r1,#0x100adcr1,r1,#0xffffff00 -> sbcr1,r1,#0xffandr1,r1,#0xffffff00 -> bicr1,r1,#0xff
这样,一些原本非法的立即数也可以正常编译通过。如果一个立即数,经过上述转换后是合法的,那么它也可以用在数据操作指令中。(3)寄存器移位寻址ASR 算术右移LSL 逻辑左移LSR 逻辑右移
ROR循环右移RRX 扩展的循环右移(3)寄存器移位寻址(续)如果移位的位数由立即数(5bit,取值范围0-31)给出,就叫作immediatespecifiedshift;如果由Rs的低5位决定,就叫做registerspecifiedshift。Registerspecifiedshift的两点问题:不能使用pc:如果将pc寄存器用在Rn,Rd,Rm和Rs的位置上时,会产生不可预知的结果。额外代价(overhead):需要更多的周期才能完成指令,因为ARM没有能力一次读取3个寄存器。Immediatespecifiedshift没有上述问题。(3)寄存器移位寻址(续)在registerspecifiedshift寻址方式下使用pc寄存器,编译器提示如下警告:在ADS1.2种编译产生如下警告之一:WarningA1477W:ThisregistercombinationresultsinUNPREDICTABLEbehaviorWarning:A1320E:Undefinedeffect(usingPCasRnorRminregisterspecifiedshift)Warning:A1319E:Undefinedeffect(usingPCasRs)但是在arm-elf-gcc-2.95.3中没有报告错误。(4)后缀s数据处理指令可以选择s后缀,以影响状态标志。但是比较指令(cmp、cmn、tst和teq)不需要后缀s,它们总会直接影响cpsr中的状态标志。在数据操作指令中,除了比较指令以外,其它的指令如果带有s后缀,同时又以pc为目标寄存器进行操作,则操作的同时从spsr恢复cpsr。比如:movspc,#0xff /*cpsr=spsr;pc=0xff*/addspc,r1,#0xffffff00/*cpsr=spsr;pc=r1+0xffffff00*/andspc,r1,r2 /*cpsr=spsr;pc=r1&r2;*/如果在user或者system模式下使用带有s后缀的数据操作指令,同时以pc为目标寄存器,那么会产生不可预料的结果。因为user和system模式下没有spsr。3.3.3数据传输指令语法<Operation>{<cond>}{s}<Rd>,#<immed><Operation>{<cond>}{s}<Rd>,<Rm><Operation>{<cond>}{s}<Rd>,<Rm>,LSL#<immed_5><Operation>{<cond>}{s}<Rd>,<Rm>,LSL<Rs>伪代码
ifConditionPassed(cond)then Rd=第2操作数
ifs==1andRd==pcthen
cpsr==spsr elseifs==1then setNZCVflagsincpsr3.3.3数据传输指令(续)举例mov r0,r1 /*r0=r1,不修改cpsr*/mov r0,#0x0 /*r0=0,不修改cpsr*/movs r0,#0x0 /*r0=0,同时设置cpsr的Z位*/movs r0,#-10 /*r0=0xfffffff6,同时设置cpsr的N位*/mvn r0,r2 /*r0=NOTr2,不修改cpsr*/mvn r0,0xffffffff /*r0=0x0,不修改cpsr*/mvns r0,0xffffffff /*r0=0x0,同时设置cpsr的Z位*/mov r0,r1,LSL#1 /*r0=r1<<1*/mov r0,r1,LSRr2
/*r0=r1>>r2*/3.3.3数据传输指令(续)说明mvn意为“取反传输”,它把源寄存器的每一位取反,将得到的结果写入结果寄存器。movs和mvns指令对pc寄存器赋值时有特殊含义,表示要求在赋值的同时从spsr中恢复cpsr。对于mov和mvn指令,编译器会进行智能的转化。比如指令“movr1,0xffffff00”中的立即数是非法的。在编译时,编译器将其转化为“mvnr1,0xff”,这样就不违背立即数的要求。所以对于mov和mvn指令,可以认为:合法的立即数反码也是合法的立即数。3.3.4算术指令语法<Operation>{<cond>}{s}<Rd>,<Rn>,#<immed><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm>,LSL#<immed_5><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm>,LSL<Rs>伪代码(以加法add为例)
ifConditionPassed(cond)then Rd=Rn+第2操作数
ifs==1andRd==pcthen
cpsr=spsr elseifs==1then setNZCVflagsincpsr3.3.4算术指令(续)举例add r0,r1,r2 /*r0=r1+r2*/adc r0,r1,r2 /*r0=r1+r2+carry*/sub r0,r1,r2 /*r0=r1–r2*/sbc r0,r1,r2 /*r0=r1–r2+carry-1*/rsb r0,r1,r2 /*r0=r2–r1*/rsc r0,r1,r2 /*r0=r2–r1+carry–1*/add r0,r1,r1,LSL#31 /*r0=r1+r1<<31*/add r0,r1,r1,LSLr2 /*r0=r1+r1<<r2*/说明adds和adcs在进位时将cpsr的C标志置1;否则置0。subs和sbcs在产生借位时将cpsr的C标志置0;否则置1。3.3.5逻辑指令语法<Operation>{<cond>}{s}<Rd>,<Rn>,#<immed><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm>LSL#<immed_5><Operation>{<cond>}{s}<Rd>,<Rn>,<Rm>LSL<Rs>伪代码(以and为例)
IfConditionPassed(cond)then Rd=RnAND第2操作数
ifs==1andRd==pcthen
cpsr=spsr elseifs==1then setNZCVflagsincpsr3.3.5逻辑指令(续)举例and r0,r1,r2 /*r0=r1ANDr2*/and r1,r1,#0xffffff00/*r1=r1AND0xffffff00*/orr r0,r1,r2 /*r0=r1ORr2*/eor r0,r1,r2/*r0=r1XORr2*/bic r0,r1,r2 /*r0=r1ANDNOTr2*/bic r1,r1,#0x0f /*清空r1的低4位*/and r0,r1,r1,LSL#31 /*r0=r1AND(r1<<31)*/and r0,r1,r1,LSRr2 /*r0=r1AND(r1>>r2)*/3.3.6比较指令语法<Operation>{<cond>}<Rn>,#<immed><Operation>{<cond>}<Rn>,<Rm><Operation>{<cond>}<Rn>,<Rm>,LSL#<immed_5><Operation>{<cond>}<Rn>,<Rm>,LSL<Rs>伪代码(以cmp为例)
IfConditionPassed(cond)then
alu_out=Rn–第2操作数
setNZCVflagsincpsr3.3.6比较指令(续)举例cmp r1,r2/*根据r1–r2的结果设置cpsr,结果不写回*/cmn r1,r2/*根据r1+r2的结果设置cpsr,结果不写回*/tst r1,r2/*根据r1ANDr2的结果设置cpsr,结果不写回*/teq r1,r2/*根据r1XORr2的结果设置cpsr,结果不写回*/cmp r2,#5/*根据r2–5的结果设置cpsr,结果不写回*/cmp r1,r2,LSL#5 /*根据r1–(r2<<5)设置cpsr*/cmp r1,r2,LSLr3 /*根据r1–(r2<<r3)设置cpsr*/
说明如果不考虑结果的写回,cmp、cmn、tst和teq分别等价于subs、adds、ands和eors。3.3.7乘法指令MUL32位乘法MLA32位带加数的乘法指令SMULL64位有符号数乘法指令SMLAL64位带加数的有符号数乘法指令UMULL64位无符号数乘法指令UMLAL64位带加数的无符号数乘法指令MUL{<cond>}{s}<Rd>,<Rm>,<Rs>MLA{<cond>}{s}<Rd>,<Rm>,<Rs>,<Rn>SMULL{<cond>}{s}<RdLo>,<RdHi>,<Rm>,<Rs>SMLAL{<cond>}{s}<RdLo>,<RdHi>,<Rm>,<Rs>UMULL{<cond>}{s}<RdLo>,<RdHi>,<Rm>,<Rs>UMLAL{<cond>}{s}<RdLo>,<RdHi>,<Rm>,<Rs>MULR0,R1,R2;R0=R1*R2MLAR0,R1,R2,R3;R0=R1*R2+R3SMULLR1,R2,R3,R4;R1=R3*R4(低32位);R2=R3*R4(高32位)SMLALR1,R2,R3,R4;R2R1=R3*R4+R2R1UMULLR1,R2,R3,R4;R2R1=R3*R4UMLALR1,R2,R3,R4;R2R1=R3*R4+R2R13.3.7杂类的算术指令CLZ前导0个数计算指令,用于计算操作数最高端0的个数。计算操作数规范化时需要左移的位数。确定一个优先级掩码中最高优先级。CLZ{<cond>}<Rd>,<Rm>3.4程序状态访问指令3.4程序状态访问指令当需要修改cpsr/spsr的内容时,首先要读取它的值到一个通用寄存器,然后修改某些位,最后将数据写回到状态寄存器。cpsr/spsr不是通用寄存器,不能使用mov指令来读写。在ARM处理器中,只有mrs指令可以读取cpsr/spsr;只有msr可以写cpsr/spsr。程序状态寄存器
条件标识位N=
结果为负Z=结果为零C=进位V=溢出Q标识位只在5TE/J系列中有效指示stickyoverflow的发生J标识位仅在5TEJ系列中有效J=1:处理器处于Jazelle状态中断使能位I=1:禁止IRQ.F=1:禁止FIQ.T标识位只在xT
系列内核中有效T=0:处理器处于ARM状态T=1:处理器处于Thumb状态模式位指示当前处理器模式2731NZCVQ2867IFTmode162381554024fsxc
UndefinedJ3.4.1读指令mrs语法mrs{<cond>}<Rd>,cpsr|spsr伪代码
ifConditionPassed(cond)then ifR==1then Rd=spsr else Rd=cpsr3.4.1读指令mrs(续)举例mrs r0,cpsr /*读取cpsr到r0*/mrs r3,spsr /*读取spsr到r3*/说明user和system模式没有spsr,因此这些模式下不能读取spsr。3.4.2写指令msr的二进制格式0condR10fsxc1111操作数01112151619202122102324#25002627283118位立即数#rot0781100000000Rm03411cpsr/spsr域屏蔽立即数对准操作数寄存器(1)写指令msr的语法msr{<cond>}<psr>_<fields>,#<immed>msr{<cond>}<psr>_<fields>,<Rm><immed>表示合法的立即数:8bit循环右移偶数位<psr>代表cpsr或spsr<fields>指定传送的区域,可进一步细分(只能小写)c 控制域字节(psr[7:0])x 扩展域字节(psr[15:8]) s 状态域字节(psr[23:16])f 标志域字节(psr[31:24]) (2)写指令msr的伪代码伪代码ifConditionPassed(cond)then ifopcode[25]==1 operand=8立即数Rotate_Right(#rot*2) else/*opcode[25]==0*/operand=Rm ifR==0then iffield_mask[0]==1andInAPrivilegeMode()thencpsr[7:0]=operand[7:0] iffield_mask[1]==1andInAPrivilegeMode()thencpsr[15:8]==operand[15:8] iffield_mask[2]==1andInAPrivilegeMode()thencpsr[23:16]==operand[23:16] iffield_mask[3]==1thencpsr[31:24]=operand[31:24] else/*R==1*/ iffield_mask[0]==1andCurrentModeHasSPSR()thenspsr[7:0]=operand[7:0] iffield_mask[1]==1andCurrentModeHasSPSR()thenspsr[15:8]==operand[15:8] iffield_mask[2]==1andCurrentModeHasSPSR()thenspsr[23:16]==operand[23:16] iffield_mask[3]==1andCurrentModeHasSPSR()thenspsr[31:24]=operand[31:24](3)msr举例和说明举例msr
cpsr_c,#0xd3 /*切换到SVC模式*/msr
cpsr_cxsf,r3 /*cpsr=r3*/说明user和system模式没有spsr,因此这些模式下不能对spsr操作。由于权限问题,在user模式下对cpsr[23:0]修改无效。如果使用立即数,要使用合法的立即数。程序不能同过“msr修改cpsr的T位”来完成ARM/Thumb态的切换。必须使用bx指令,因为bx属于分支指令,它会打断流水线,实现处理器状态切换。如果要修改读出的值,仅修改必要的位,其它位保持不变,这样保持了最大兼容性。
mrsr14,CPSR;gettheprocessorstatus
bicr14,r14,#CPSR_Mode_Mask
orrr14,r14,#(CPSR_Mode_SVC:OR:CPSR_Int_Mask)
msrcpsr_cf,r14;SVC32modewithinterruptsdisabled3.5跳转指令3.5跳转指令语法b{<cond>}labelbl{<cond>}label说明寻址范围+32MB3.5跳转指令(续)当转移指令执行时,处理器将指令中的offset(24bit)左移2bit,变成26bit,表示+32M的范围。pc从新的地址执行,流水线重新填充。如果是“bl”指令,将返回地址写入lr寄存器。子程序返回时只需要用lr恢复pc就可以:movpc,lr“b”指令不影响lr寄存器
ENTRY;;Exceptionvectors;VectortablebReset_Handler
Exceptions
ldrpc,Undefined_Handler_addr
ldrpc,SWI_Handler_addr
ldrpc,Prefetch_Handler_addr
ldrpc,Abort_Handler_addr
nop
ldrpc,IRQ_Handler_addr
ldrpc,FIQ_Handler_addrVectortableEnd
VectorTableVectortablecanbeat
0xFFFF0000onARM720T
andonARM9/10familydevicesFIQIRQ(Reserved)DataAbortPrefetchAbortSoftwareInterruptUndefinedInstructionReset0x1C0x180x140x100x0C0x080x040x00异常处理3.6单数据访存指令3.6单数据访存指令第一类:读写字: ldr/str读写无符号字节: ldrb/strb第二类:读写无符号半字: ldrh/strh读有符号半字: ldrsh读有符号字节: ldrsb3.6.1第一类指令的指令格式0000000000Rm03411方式2:Rm例子:ldrr0,[r1,+r2]011#immed_12方式1:#immed_12(取值范围0–0xfff)例子:ldrr0,[r1,#+0xfff]shiftRm03411#immed_567方式3:RmLSL#immed_5(取值范围0-31)例子:ldrr0,[r1,r2LSL#31]050/1:str/ldr0/1:无/有(!)0/1:后变址/前变址0/1:字/无符号字节condRnRd第2操作数07811121516192022012728312324UBWL2126PI250/1:加/减(第2操作数)0/1:立即数(方式1)/寄存器(方式2,3)3.6.2第一类指令的语法语法ldr|str{<cond>}{b}<Rd>,[<Rn>,#+<immed_12]{!}ldr|str{<cond>}{b}<Rd>,[<Rn>,+<Rm>]{!}ldr|str{<cond>}{b}<Rd>,[<Rn>,+<Rm>,<shift>#<immed_5>]{!}ldr|str{<cond>}{b}<Rd>,[<Rn>],#+<immed_12ldr|str{<cond>}{b}<Rd>,[<Rn>],+<Rm>ldr|str{<cond>}{b}<Rd>,[<Rn>],+<Rm>,<shift>#<immed_5>举例ldrbr0,[r1,#+0xfff]/*把r1+0xfff地址的字节读入r0*/ldrr0,[r1,+r2]! /*把r1+r2地址的32比特数读入r0,然后r1=r1+r2*/strr0,[r1,+r2,LSL#31] /*把r0(32bit)写到地址r1+(r2<<31)*/ldrr0,[r1],#+0xfff /*把r1地址的数读入r0,然后r1=r1+0xfff*/ldrr0,[r1],+r2 /*把r1地址的数读入r0,然后r1=r1+r2*/ldrr0,[r1],+r2,LSL#31/*把r1地址的数读入r0,然后r1=r1+(r2<<31)*/3.6.2第一类指令说明说明ldr/str
读/写一个32bit字到/从一个32bit的寄存器,要求读/写地址字对齐。ldrb:读一个8bit字节到一个32bit的寄存器,不要求地址对齐,寄存器的高24位清零。strb:将寄存器的低8位,写入内存的某个地址。不要求地址对齐。3.6.3第二类指令语法同第一类指令说明ldrh:读取16bit半字到一个32bit寄存器,要求地址半字对齐,目标寄存的高16bit清零。strh:将寄存器的低16bit存放到内存中,要求地址半字对齐。ldrsh:将内存中的一个16bit半字读到一个32bit寄存器中,要求地址半字对齐。寄存器高16bit根据符号位扩展。ldrsb:将内存中的一个8bit字节读到一个32bit寄存器中,寄存器高24bit根据符号位扩展。不要求地址对齐。3.6.4前/后变址0000000000Rm03411方式2:Rm例子:ldrr0,[r1,+r2]011#immed_12方式1:#immed_12(取值范围0–0xfff)例子:ldrr0,[r1,#+0xfff]shiftRm03411#immed_567方式3:RmLSL#immed_5(取值范围0-31)例子:ldrr0,[r1,r2LSL#31]050/1:str/ldr0/1:无/有(!)0/1:后变址/前变址0/1:字/无符号字节condRnRd第2操作数07811121516192022012728312324UBWL2126PI250/1:加/减(第2操作数)0/1:立即数(方式1)/寄存器(方式2,3)(1)简单的基址寻址基址寄存器数据访问strr0,[r1]ldrr2,[r1](2)前变址寻址strr0,[r1,#12];/*{!}mem32[r1+12]=r0;r1=r1;/*{r1=r1+12;}(3)后变址寻址数据访问strr0,[r1],#12mem32[r1]=r0;r1=r1+12;3.6.5
三种寻址方式(第一类)0000000000Rm03411方式2:Rm例子:ldrr0,[r1,+r2]011#immed_12方式1:#immed_12(取值范围0–0xfff)例子:ldrr0,[r1,#+0xfff]shiftRm03411#immed_567方式3:RmLSL#immed_5(取值范围0-31)例子:ldrr0,[r1,r2LSL#31]050/1:str/ldr0/1:无/有(!)0/1:后变址/前变址0/1:字/无符号字节condRnRd第2操作数07811121516192022012728312324UBWL2126PI250/1:加/减(第2操作数)0/1:立即数(方式1)/寄存器(方式2,3)3.6.5寻址方式1—立即数变址寻址ldr|str{<cond>}{b}<Rd>,[<Rn>,#+<immed_12>]{!}ldr|str{<cond>}{b}<Rd>,[<Rn>],#+<immed_12>说明:无叹号的前变址,当pc作为Rn时,内存基地址为当前指令地址加8字节偏移;后变址或有叹号的前变址,当pc作为Rn时,会产生不可预知的结果在ADS1.2中,提示错误Error:A1324EUndefinedeffect(PC+writeback)在arm-elf-gcc-2.95.3中,没有提示后变址或有叹号的前变址,如果Rn和Rd是同一个寄存器,编译出错在ADS1.2中,提示错误Error:A1325E:Undefinedeffect(destinationsameaswritten-backbase)在arm-elf-gcc-2.95.3中,提示Warning:destinationregistersameaswrite-backbase如果immed_12超过0xfff,编译会出错在ADS1.2中,提示错误Error:A1174E:Datatransferoffsetoutofrange在arm-elf-gcc-2.95.3中,提示Error:addressoffsettoolarge3.6.5寻址方式2—寄存器变址寻址ldr|str{<cond>}{B}<Rd>,[<Rn>,+<Rm>]{!}ldr|str{<cond>}{B}<Rd>,[<Rn>],+<Rm>说明:无论如何,pc都不能作Rm。无叹号的前变址,当pc作为Rn时,内存基地址为当前指令地址加8字节偏移;后变址或有叹号的前变址,当pc作为Rn时,会产生不可预知的结果。后变址或有叹号的前变址,如果Rn和Rd是同一个寄存器,会出现不可预知的结果。3.6.5寻址方式3-寄存器移位变址寻址ldr|str{<cond>}{B}<Rd>,[<Rn>,+<Rm>,<shift>#<immed_5>]{!}ldr|str{<cond>}{B}<Rd>,[<Rn>],+<Rm>,<shift>#<immed_5>说明:无论如何,pc都不能作Rm。无叹号的前变址,当pc作为Rn时,内存基地址为当前指令地址加8字节偏移;后变址或有叹号的前变址,当pc作为Rn时,会产生不可预知的结果。后变址或有叹号的前变址,如果Rn和Rd是同一个寄存器,会出现不可预知的结果。如果immed_5超过31,编译器报错。3.7多数据访存指令3.7多数据访存指令批量访存指令可以实现一组(1-16)寄存器和一块(4-64字节)连续内存单元之间的数据传输。3.7.1指令格式3.7.2ldm/stm指令的语法语法ldm|stm{<cond>}<addressing_mode><Rn>{!},<registers>{^}<addressing_mode>有4种:IA(IncrementAfter) 事后递增IB(IncrementBefore) 事先递增DA(DecrementAfter) 事后递减DB(DecrementBefore) 事先递减例子ldmiar0,{r5-r8} /*将内存中(r0)到(r0+12)4个字读取到r5~r8的4个寄存器中*/ldmibr0,{r5-r8}/*将内存中(r0+4)到(r0+16)4个字读取到r5~r8的4个寄存器中*/ldmdar0,{r5-r8}/*将内存中(r0-12)到(r0)4个字读取到r5~r8的4个寄存器中*/ldmdbr0,{r5-r8}/*将内存中(r0-16)到(r0)4个字读取到r5~r8的4个寄存器中*/3.7.2ldm/stm指令的语法(续)说明递增方式和递减方式处理寄存器列表和内存地址对应关系时采用不同的顺序,见前面的例子。可以总结为:编号低的寄存器对应低内存地址。pc不能作为stm指令的<Rn>,否则结果不可预知。感叹号“!”表示执行后将更新<Rn>。“^”不能在usr和system模式下使用,否则结果不可预知。在其它模式下使用时,含义和寄存器列表是否包含pc有关。3.7.3ldm指令的三种用法编号!^pcldm指令不同的功能用法1是是是同(5),但是更新<Rn>32是是否编译警告(ADS1.2):Warning:A1329W:Unsafeinstruction(forcedusermodexferwithwrite-backtobase)23是否是同(7),但是更新<Rn>14是否否同(8),但是更新<Rn>,且<Rn>不能出现在<registers>中15否是是数据读取的同时,拷贝spsr到cpsr36否是否<registers>采用user模态下的寄存器27否否是同(8),可用于程序跳转。18否否否正常读取13.7.4stm指令的两种用法编号!^ldm指令不同的功能用法1是是同(3),但是更新<Rn>22是否同(4),但是更新<Rn>。当<Rn>是<registers>中编号最小的寄存器时,指令将<Rn>的初值保存;否则结果不可预测。13否是<registers>采用user模态下的寄存器24否否正常写入13.7.5多数据访存的程序例子/*r12指向源数据起点*//*r14指向源数据终点*//*r13指向目标地址*/loop:
ldmiar12!,{r0-r11} /*读48字节*/
stmiar13!,{r0-r11} /*写48字节*/
cmpr12,r14 /*是否到末尾*/
bneloop /*重复循环*/3.7.6模拟栈ARM指令集中没有用于栈的操作指令,但是可以用多数据访存指令来模拟。(1)栈的分类栈的分类(按指针):栈指针指向最后一个被占用的地址
(FullStack)在push前需要先将栈指针减小栈指针指向下一个被占用的地址
(EmptyStack)在push之后需要将栈指针减小栈的分类(按方向):上升的栈(AscendingStack)向高地址扩展下降的栈(DescendingStack)向低地址扩展(2)模拟压栈操作块数据访问指令栈访问指令说明stmdastmed下降型空栈stmiastmea上升型空栈stmdbstmfd下降型满栈stmibstmfa上升型满栈(3)模拟退栈操作块数据访问指令栈访问指令说明ldmdaldmfa上升型满栈ldmialdmfd下降型满栈ldmdbldmea上升型空栈ldmibldmed下降型空栈(4)模拟栈操作模拟stack的访问stmfd/ldmfd :FullDescendingStackstmfa/ldmfa :FullAscendingStack.stmed/ldmed :EmptyDescendingStackstmea/ldmea :EmptyAscendingStack常见的情况stmfdsp!,{r0-r12,lr}//保存所有有寄存器(包括返回地址)……ldmfdsp!,{r0-r12,pc}//恢复所有寄存器(包括pc)(5)栈操作图示3.8其它指令3.8其它指令信号量操作指令:用于进程间的同步和互斥,提供对信号量的原子操作。异常中断产生指令:用于系统调用和调试。3.8.1信号量操作指令语法swp|swpb{<cond>}<Rd>,<Rm>,[<Rn>]例子swpr1,r2,[r3] /*将内存单元(r3)中的字读取到r1,同时将r2中的数据写入内存单元(r3)中*/swpr1,r1,[r2] /*将r1寄存器内容和内存单元(r2)的内容互换*/说明swpb读取8bit数据到寄存器后会对高24位清零,写到内存的8bit数来自寄存器低8位3.8.1信号量操作指令(续)3.8.2异常产生指令指令格式语法swi{<cond>}<immed_24>说明利用这种机制实现用户模式对操作系统特权模式的程序调用,主要用于用户程序调用操作系统的API。参数传递通常有两种方法:指令中的24bit立即数指定API号,参数通过寄存器传递。忽略指令中的24bit立即数,r0指定API号,其它参数通过其它寄存器传递。condImmed_240231111272831243.8.3中断产生指令语法bkpt<immed_16>说明用于产生软件断点中断。主要用于调试。ARMv5及以上版本支持。3.8.4协处理器指令ARM支持16个协处理器。ARM协处理器指令包含3类:用于ARM处理器初始化ARM协处理器的数据处理操作;用于ARM处理器寄存器和ARM协处理器寄存器之间的数据传送操作;用于在ARM协处理器的寄存器和内存单元之间传送数据。CDP协处理器数据操作指令LDC协处理器数据读取指令STC协处理器数据写入指令MCRARM寄存器到协处理器寄存器的数据传送指令MRC协处理器寄存器到ARM寄存器的数据传输指令3.9伪指令3.9伪指令在ARM汇编语言源程序中有些特殊助记符,它们没有相对应的操作码或者机器码,通常称为伪指令,它们所完成的操作称为伪操作。伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,由汇编程序在源程序的汇编期间进行处理,仅在汇编过程中起作用。符号定义伪指令数据定义伪指令汇编控制伪指令信息报告伪指令宏指令以及其他伪指令。3.9.1符号定义伪指令Ⅰ用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等。用于定义局部变量的LCLA、LCLL、LCLS;
用于定义全局变量的GBLA、GBLL、GBLS
;用于对变量赋值的SETA、SETL、SETS
;为通用寄存器列表定义名称的RLIST。
3.9.1符号定义伪指令Ⅱ
1.
LCLA、LCLL、LCLS格式:LCLA/LCLL/LCLS 局部变量名说明:LCLA、LCLL、LCLS伪指令用于定义一个汇编程序中的局部变量,并初始化,其中:LCLA定义一个局部的数字变量,初始化为0;LCLL定义一个局部的逻辑变量,初始化为F;LCLS定义一个局部的字符串变量,初始化为空串;这三条伪指令用于声明局部变量,在其局部作用范围内变量名必须唯一。3.9.1符号定义伪指令Ⅲ
2.
GBLA、GBLL、GBLS格式:GBLA/GBLL/GBLS 变量名说明:GBLA、GBLL、GBLS伪操作定义一个汇编程序中的全局变量,并初始化,其中:GBLA定义一个全局数字变量,并初始化为0;GBLL定义一个全局逻辑变量,并初始化为“F”;GBLS定义一个全局字符串变量,并初始化为空串;
这三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。
3.9.1符号定义伪指令Ⅳ
3.SETA、SETL、SETS格式:变量名 SETA/SETL/SETS 表达式说明:SETA:给一个数字变量赋值;SETL:给一个逻辑变量赋值;SETS:给一个字符串变Ⅳ量赋值;格式中的变量名必须为已经定义过的全局或局部变量,表达式为将要赋给变量的值。
3.9.1符号定义伪指令Ⅴ4.RLIST格式:名称 RLIST {寄存器列表}说明:RLIST可用于对一个通用寄存器列表定义名称,该名称可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器为根据寄存器的编号由低到高访问次序,与列表中的寄存器排列次序无关。
3.9.2数据定义伪指令Ⅰ用于为数据分配存储单元,同时也可完成已分配存储单元的初始化。
DCB DCW/DCWUDCD/DCDUDCQ/DCQUDCFS/DCFSUDCFD/DCFDUSPACEFIELDMAP 3.9.2数据定义伪指令Ⅱ1.
DCB:
标号DCB表达式
说明:DCB用于分配一块字节单元并用伪指令中指定的表达式进行初始化。其中,表达式可以为使用双引号的字符串或0——255的数字,DCB可用“=”代替。
2.
DCW/DCWU:
标号DCW/DCWU表达式说明:DCW分配一段半字存储单元并用表达式值初始化,它定义的存储空间是半字对齐的。3.9.2数据定义伪指令Ⅲ3.
DCD/DCDU:
标号 DCD/DCDU表达式说明:DCD伪指令用于分配一块字存储单元并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。DCD也可用“&”代替。
4.
DCQ/DCQU:标号DCQ/DCQU表达式说明:DCQ用于分配一块以8个字节为单位的存储区域并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。DCQU功能跟DCQ类似,只是分配的存储单元不严格字对齐。
3.9.2数据定义伪指令Ⅳ5.
DCFD/DCFDU:
标号 DCFD/DCFDU 表达式说明:DCFD用于为双精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的,每个双精度的浮点数占据两个字单元。DCFDU功能跟DCFD类似,只是分配的存储单元不严格字对齐。6.
DCFS/DCFSU:
标号 DCFS/DCFSU 表达式说明:DCFS用于为单精度的浮点数分配一片连续的字存储单元并用表达式初始化,它定义的存储空间是字对齐的,每个单精度浮点数使用一个字单元.DCFSU功能跟DCFS类似,只是分配的存储单元不严格字对齐。
3.9.2数据定义伪指令Ⅴ7.
SPACE:
标号 SPACE 表达式说明:SPACE用于分配一片连续的存储区域并初始化为0,表达式为要分配的字节数,SPACE也可用“%”代替。
8.
MAP:MAP 表达式[,基址寄存器]
说明:MAP定义一个结构化的内存表的首地址,“^”可以用来代替MAP。9.
FILED:
标号 FIELD 字节数说明:FIELD用于定义一个结构化内存表中的数据域,“#”可用来代替FILED。
3.9.3汇编控制伪指令Ⅰ汇编控制伪操作用于指引汇编程序的执行流程:
MACRO、MEND
IF、ELSE、ENDIF
WHILE、WEND
MEXIT3.9.3汇编控制伪指令Ⅱ1.
MACRO、MENDMACRO[$标号] 宏名 [$参数1,$参数2,……]
指令序列
MEND
说明:MACRO表明一个宏定义的开始,MEND则表示一个宏的结束,MACRO、MEND前呼后应可以将一段代码定义为一个整体,又称宏,然后就可以在程序中通过宏的名称及参数调用该段代码。
MACRO和MEND之间的代码称为宏定义体,在宏定义体的第一行声明宏的原型,宏的原型包含宏名、所需的参数。在源程序被编译时,汇编器将宏调用展开,用宏定义中的指令序列替换程序中的宏调用,并将实际参数的值传递给宏定义中的参数。注意宏操作可以嵌套使用,并可以在编译时用选项加以控制。
3.9.3汇编控制伪指令Ⅲ2.IF、ELSE、ENDIFIF 逻辑表达式 代码段1ELSE
代码段2ENDIF说明:IF、ELSE、ENDIF伪操作能根据逻辑表达式的成立与否决定是否在编译时加入某个指令序列。IF、ELSE、ENDIF可以分别用“[”、“|”、“]”代替。IF、ELSE、ENDIF伪指令可以嵌套使用。
3.9.3汇编控制伪
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 辽宁铁道职业技术学院《规则与裁判法》2023-2024学年第一学期期末试卷
- 兰州城市学院《建筑设备施工安装技术》2023-2024学年第一学期期末试卷
- 江西电力职业技术学院《智慧工地》2023-2024学年第一学期期末试卷
- 湖南第一师范学院《篆刻3》2023-2024学年第一学期期末试卷
- 黑龙江生态工程职业学院《风景建筑速写》2023-2024学年第一学期期末试卷
- 重庆护理职业学院《民事诉讼法学(含模拟法庭)》2023-2024学年第一学期期末试卷
- 中央财经大学《人工智能专业前沿》2023-2024学年第一学期期末试卷
- 郑州软件职业技术学院《英语模拟课堂》2023-2024学年第一学期期末试卷
- 小学2024年体育发展年度报告
- 浙江电力职业技术学院《生物信息学前沿技术》2023-2024学年第一学期期末试卷
- 关于斗争精神不足的整改措施【三篇】
- 初三物理寒假课程
- 如何预防心脑血管病
- LY/T 3321-2022草原生态价值评估技术规范
- 《新媒体文案创作与传播》期末试卷1
- 人感染H7N9禽流感流行病学调查和处置
- 高等院校内部控制多模型决策方法研究
- 木栈道专项施工方案(同名3601)
- GB/T 11957-2001煤中腐植酸产率测定方法
- 浙江省普通高中通用技术学科教学指导意见
- HRB500级钢筋施工要点ppt课件
评论
0/150
提交评论