thumb指令集是arm指令集的一个子集,是针对代码密度问题而提出的,它具有16位的代码宽度。与等价的32位代码相比较,thumb指令集在保留32位代码优势的同时,大大的节省了系统的存储空间。thumb不是一个完整的体系结构,不能指望处理器只执行thumb指令集而不支持arm指令集。
thumb指令分类
thumb指令集分为:分支指令、数据传送指令、单寄存器加载和存储指令以及多寄存器加载和存储指令。thumb指令集没有协处理器指令、信号量(semaphore)指令以及访问cpsr或spsr的指令。[1] 1. 存储器访问指令 (1)dr和str--立即数偏移 加载寄存器和存储寄存器。存储器的地址以一个寄存器的立即数偏移(immediate offset)指明。 指令格式: op rd, n,#immed_5×4] oph rd, n,#immed_5×2] opb rd, n,#immed_5×1] 其中: op:为dr或str。 h:指明无符号半字传送的参数。 b:指明无符号字节传送的参数。 rd:加载和存储寄存器。rd 必须在r0~r7范围内。 rn:基址寄存器。rn 必须在r0~r7范围内。 immed_5×n:偏移量。它是一个表达式,其取值(在汇编时)是n的倍数,在(0~31)*n范围内,n=4、2、1。 str:用于存储一个字、半字或字节到存储器中。 dr:用于从存储器加载一个字、半字或字节。 rn:rn中的基址加上偏移形成操作数的地址。 立即数偏移的半字和字节加载是无符号的。数据加载到rd的最低有效字或字节,rd 的其余位补0。 字传送的地址必须可被4整除,半字传送的地址必须可被2整除。 指令示例: dr r3,5,#0] strb r0,3,#31] strh r7,3,#16] drb r2,4,#1abe-{pc}] (2)dr和str--寄存器偏移 加载寄存器和存储寄存器。用一个寄存器的基于寄存器偏移指明存储器地址。 指令格式: op rd,n,rm] 其中,op 是下列情况之一: dr:加载寄存器,4字节字。 str:存储寄存器,4字节字。 drh:加载寄存器,2字节无符号半字。 drsh:加载寄存器,2字节带符号半字。 strh:存储寄存器,2字节半字。 drb:加载寄存器,无符号字节。 drsb:加载寄存器,带符号字节。 strb:存储寄存器,字节。 rm:内含偏移量的寄存器,rm必须在r0~r7范围内。 带符号和无符号存储指令没有区别。 str指令将rd中的一个字、半字或字节存储到存储器。 dr指令从存储器中将一个字、半字或字节加载到rd。 rn中的基址加上偏移量形成存储器的地址。 寄存器偏移的半字和字节加载可以是带符号或无符号的。数据加载到rd的最低有效字或字节。对于无符号加载,rd的其余位补0;或对于带符号加载,rd的其余位复制符号位。字传送地址必须可被4整除,半字传送地址必须可被2整除。 指令示例: dr r2,,r5] drsh r0,0,r6] strb r,7,r0] (3)dr和str--pc或sp相对偏移 加载寄存器和存储寄存器。用pc或sp中值的立即数偏移指明存储器中的地址。没有pc相对偏移的str指令。 指令格式: dr rd,c,#immed_8×4] dr rd,be dr rd,sp,#immed_8×4] str rd, p,#immed_8×4] 其中: immed_8×4:偏移量。它是一个表达式,取值(在汇编时)为4的整数倍,范围在0~1020之间。 abe:程序相对偏移表达式。abe必须在当前指令之后且1kb范围内。 str:将一个字存储到存储器。 dr:从存储器中加载一个字。 pc或sp的基址加上偏移量形成存储器地址。pc的位]被忽略,这确保了地址是字对准的。字或半字传送的地址必须是4的整数倍。 指令示例: dr r2,c,#1016] dr r5,ocadata dr r0,p,#920] str r,p,#20] (4)push和pop 低寄存器和可选的r进栈以及低寄存器和可选的pc出栈。 指令格式: push {regist} pop {regist} push {regist,r} pop {regist,pc} 其中: regist:低寄存器的全部或其子集。 括号是指令格式的一部分,它们不代表指令列表可选。列表中至少有1个寄存器。thumb堆栈是满递减堆栈,堆栈向下增长,且sp指向堆栈的最后入口。寄存器以数字顺序存储在堆栈中。最低数字的寄存器存储在最低地址处。 pop {regist,pc}这条指令引起处理器转移到从堆栈弹出给pc的地址,这通常是从子程序返回,其中r在子程序开头压进堆栈。这些指令不影响条件码标志。 指令示例: push {r0,r3,r5} push {r1,r4-r7} push {r0,r} pop {r2,r5} pop {r0-r7,pc} (5)dmia和stmia 加载和存储多个寄存器。 指令格式: op rn!,{regist} 其中,op为dmia或stmia。 regist为低寄存器或低寄存器范围的、用逗号隔开的列表。括号是指令格式的一部分,它们不代表指令列表可选,列表中至少应有1个寄存器。寄存器以数字顺序加载或存储,最低数字的寄存器在rn的初始地址中。 rn的值以regist中寄存器个数的4 倍增加。若rn在寄存器列表中,则: 对于dmia指令,rn的最终值是加载的值,不是增加后的地址。 对于stmia指令,rn存储的值有两种情况:若rn是寄存器列表中最低数字的寄存器,则rn存储的值为rn的初值;其他情况则不可预知,当然,regist中最好不包括rn。 指令示例: dmia r3!,{r0,r4} dmia r5!,{r0~r7} stmia r0!,{r6,r7} stmia r3!,{r3,r5,r7} 2. 数据处理指令 (1)add和sub--低寄存器 加法和减法。对于低寄存器操作,这2条指令各有如下3种形式: 两个寄存器的内容相加或相减,结果放到第3个寄存器中。 寄存器中的值加上或减去一个小整数,结果放到另一个不同的寄存器中。 寄存器中的值加上或减去一个大整数,结果放回同一个寄存器中。 指令格式: op rd,rn,rm op rd,rn,#expr3 op rd,#expr8 其中: op为add或sub。 rd:目的寄存器。它也用做“op rd,#expr8”的第1个操作数。 rn:第一操作数寄存器。 rm:第二操作数寄存器。 expr3:表达式,为取值在-7~+7范围内的整数(3位立即数)。 expr8:表达式,为取值在-255~+255范围内的整数(8位立即数)。 “op rd,rn,rm”执行rn+rm或rn-rm操作,结果放在rd中。 “op rd,rn,#expr3”执行rn+expr3或rn-expr3操作,结果放在rd中。 “op rd,#expr8”执行rd+expr8或rd-expr8操作,结果放在rd中。 expr3或expr8为负值的add指令汇编成相对应的带正数常量的sub指令。expr3或expr8为负值的sub指令汇编成相对应的带正数常量的add指令。 rd、rn和rm必须是低寄存器(r0~r7)。 这些指令更新标志n、z、c和v。 指令示例: add r3,r,r5 sub r0,r4,#5 add r7,#201 (2)add--高或低寄存器 将寄存器中值相加,结果送回到第一操作数寄存器。 指令格式: add rd,rm 其中: rd:目的寄存器,也是第一操作数寄存器。 rm:第二操作数寄存器。 这条指令将rd和rm中的值相加,结果放在rd中。 当rd和rm都是低寄存器时,指令“add rd,rm”汇编成指令“add rd,rd,rm”。若rd和rm是低寄存器,则更新条件码标志n、z、c 和v;其他情况下这些标志不受影响。 指令示例: add r12,r4 (3)add和sub--sp sp加上或减去立即数常量。 指令格式: add sp,#expr sub sp,#expr 其中:expr为表达式,取值(在汇编时)为在-508~+508范围内的4的整倍数。 该指令把expr的值加到sp 的值上或用sp的值减去expr的值,结果放到sp中。 expr为负值的add指令汇编成相对应的带正数常量的sub指令。expr为负值的sub指令汇编成相对应的带正数常量的add指令。 这条指令不影响条件码标志。 指令示例: add sp,#32 sub sp,#96 (4)add--pc或sp相对偏移 sp或pc值加一立即数常量,结果放入低寄存器。 指令格式: add rd,rp,#expr 其中: rd:目的寄存器。rd必须在r0~r7范围内。 rp:sp 或pc。 expr:表达式,取值(汇编时)为在0~1020范围内的4的整倍数。 这条指令把expr加到rp的值中,结果放入rd。 若rp是pc,则使用值是(当前指令地址+4)and &ffffffc,即忽略地址的低2位。 这条指令不影响条件码标志。 指令示例: add r6,sp,#64 add r2,pc,#980 (5)adc、sbc和mu 带进位的加法、带进位的减法和乘法。 指令格式: op rd,rm 其中: op为adc、sbc或mu。 rd:目的寄存器,也是第一操作数寄存器。 rm:第二操作数寄存器,rd、rm必须是低寄存器。 adc 将带进位标志的rd和rm的值相加,结果放在rd中,用这条指令可组合成多字加法。 sbc考虑进位标志,从rd值中减去rm的值,结果放入rd中,用这条指令可组合成多字减法。 mu进行rd和rm值的乘法,结果放入rd 中。 rd和rm必须是低寄存器(r0~r7)。 adc和sbc更新标志n、z、c和v。mu更新标志n和z。 在armv4及以前版本中,mu会使标志c和v不可靠。在armv5及以后版本中,mu不影响标志c和v。 指令示例: adc r2,r4 sbc r0,r1 mu r7,r6 (6)按位逻辑操作and、orr、eor和bic 指令格式: op rd,rm 其中: op为and、orr、eor或bic。 rd:目的寄存器,它也包含第一操作数,rd必须在r0~r7范围内。 rm:第二操作数寄存器,rm 必须在r0~r7范围内。 这些指令用于对rd和rm中的值进行按位逻辑操作,结果放在rd 中,操作如下: and:进行逻辑“与”操作。 orr:进行逻辑“或”操作。 eor:进行逻辑“异或”操作。 bic:进行“rd and not rm”操作。 这些指令根据结果更新标志n和z。 程序示例: and r1,r2 orr r0,r1 eor r5,r6 bic r7,r6 (7)移位和循环移位操作asr、s、sr和ror thumb指令集中,移位和循环移位操作作为独立的指令使用,这些指令可使用寄存器中的值或立即数移位量。 指令格式: op rd,rs op rd,rm,#expr 其中: op是下列其中之一: asr:算术右移,将寄存器中的内容看做补码形式的带符号整数。将符号位复制到空出位。 s:逻辑左移,空出位填零。 sr:逻辑右移,空出位填零。 ror:循环右移,将寄存器右端移出的位循环移回到左端。ror仅能与寄存器控制的移位一起使用。 rd:目的寄存器,它也是寄存器控制移位的源寄存器。rd必须在r0~r7范围内。 rs:包含移位量的寄存器,rs必须在r0~r7范围内。 rm:立即数移位的源寄存器,rm必须在r0~r7范围内。 expr:立即数移位量,它是一个取值(在汇编时)为整数的表达式。整数的范围为:若op是s,则为0~31;其他情况则为1~32。 对于除ror以外的所有指令: 若移位量为32,则rd清零,最后移出的位保留在标志c中。 若移位量大于32,则rd和标志c均被清零。 这些指令根据结果更新标志n和z,且不影响标志v。对于标志c,若移位量是零,则不受影响。其他情况下,它包含源寄存器的最后移出位。 指令示例: asr r3,r5 sr r0,r2,#16 ;将r2的内容逻辑右移16次后,结果放入r0中 sr r5,r5,av (8)比较指令cmp 和cmn 指令格式: cmp rn,#expr cmp rn,rm cmn rn,rm 其中: rn:第一操作数寄存器。 expr:表达式,其值(在汇编时)为在0~255 范围内的整数。 rm:第二操作数寄存器。 cmp指令从rn的值中减去expr或rm的值,cmn指令将rm和rn的值相加,这些指令根据结果更新标志n、z、c和v,但不往寄存器中存放结果。 对于“cmp rn,#expr”和cmn指令,rn和rm必须在r0~r7范围内。 对于“cmp rn,rm”指令,rn和rm可以是r0~r15中的任何寄存器。 指令示例: cmp r2,#255 cmp r7,r12 cmn r,r5 (9)传送、传送非和取负(mov、mvn和neg) 指令格式: mov rd,#expr mov rd,rm mvn rd,rm neg rd,rm 其中: rd:目的寄存器。 expr:表达式,其取值为在0~255范围内的整数。 rm:源寄存器。 mov指令将#expr或rm的值放入rd。mvn指令从rm中取值,然后对该值进行按位逻辑“非”操作,结果放入rd。neg指令取rm的值再乘以-1,结果放入rd。 对于“mov rd,#expr”、mvn和neg指令,rd和rm必须在r0~r7范围内。 对于“mov rd,rm”指令,rd和rm可以是寄存器r0~r15中的任意一个。 “mov rd,#expr”和mvn 指令更新标志n和z,对标志c或v无影响。neg指令更新标志n、z、c 和v。“mov rd,rm”指令中,若rd或rm是高寄存器(r8~r18),则标志不受影响;若rd 和rm 都是低寄存器(r0~r7),则更新标志n和z,且清除标志c和v。 指令示例: mov r3,#0 mov r0,r12 mvn r7,r1 neg r2,r2 (10)测试位tst 指令格式: tst rn,rm 其中: rn:第一操作数寄存器。 rm:第二操作数寄存器。 tst对rm和rn中的值进行按位“与”操作。但不把结果放入寄存器。该指令根据结果更新标志n和z,标志c和v不受影响。rn和rm必须在r0~r7范围内。 指令示例: tst r2,r4 3. 分支指令 (1)分支b指令 这是thumb指令集中唯一的有条件指令。 指令格式: b{cond} abe 其中,abe是程序相对偏移表达式,通常是在同一代码块内的标号。若使用cond,则abe必须在当前指令的-256~+256字节范围内。若指令是无条件的,则abe必须在±2kb范围内。若cond满足或不使用cond,则b指令引起处理器转移到abe。 abe必须在指定限制内。arm链接器不能增加代码来产生更长的转移。 指令示例: b doop beg sectb (2)带链接的长分支b指令 指令格式: b abe 其中,1abe为程序相对转移表达式。b指令将下一条指令的地址复制到r14(链接寄存器),并引起处理器转移到1abe。 b指令不能转移到当前指令±4mb以外的地址。必要时,arm链接器插入代码以允许更长的转移。 指令示例: b extract (3)分支,并可选地切换指令集bx 指令格式: bx rm 其中,rm装有分支目的地址的arm寄存器。rm的位]不用于地址部分。若rm 的位]清零,则位]也必须清零,指令清除cpsr中的标志t,目的地址的代码被解释为arm代码,bx指令引起处理器转移到rm存储的地址。若rm的位]置位,则指令集切换到thumb状态。 指令示例: bx r5 (4)带链接分支,并可选地交换指令集bx 指令格式: bx rm bx abe 其中,rm 装有分支目的地址的arm寄存器。rm的位]不用于地址部分。若rm 的位]清零,则位]必须也清零,指令清除cpsr中的标志t,目的地址的代码被解释为arm代码。abe为程序相对偏移表达式,“bx abe”始终引起处理器切换到arm状态。 bx指令可用于: 复制下一条指令的地址到r14。 引起处理器转移到abe或rm存储的地址。 如果rm的位]清零,或使用“bx abe”形式,则指令集切换到arm状态。 指令不能转移到当前指令±4mb范围以外的地址。必要时,arm链接器插入代码以允许更长的转移。 指令示例: bx r6 bx armsub 4. 中断和断点指令 (1)软件中断swi指令 指令格式: swi immed_8 其中,immed_8为数字表达式,其取值为0~255范围内的整数。 swi指令引起swi异常。这意味着处理器状态切换到arm态;处理器模式切换到管理模式,cpsr保存到管理模式的spsr中,执行转移到swi向量地址。处理器忽略immed_8,但immed_8出现在指令操作码的位:0]中,而异常处理程序用它来确定正在请求何种服务,这条指令不影响条件码标志。 指令示例: swi 12 (2)断点bkpt指令 指令格式: bkpt immed_8 其中,immed_8为数字表达式,取值为0~255范围内的整数。 bkpt指令引起处理器进入调试模式。调试工具利用这一点来调查到达特定地址的指令时的系统状态。尽管immed_8出现在指令操作码的位:0]中,处理器忽略immed_8。调试器用它来保存有关断点的附加信息。 指令示例: bkpt 67