更新时间:2023-06-07 18:52
thumb指令集是arm指令集的一个子集,是针对代码密度问题而提出的,它具有16位的代码宽度。与等价的32位代码相比较,thumb指令集在保留32位代码优势的同时,大大的节省了系统的存储空间。thumb不是一个完整的体系结构,不能指望处理器只执行thumb指令集而不支持arm指令集。
thumb指令集分为:分支指令、数据传送指令、单寄存器加载和存储指令以及多寄存器加载和存储指令。thumb指令集没有协处理器指令、信号量(semaphore)指令以及访问cpsr或spsr的指令。
1.存储器访问指令
(1)dr和str--立即数偏移 加载寄存器和存储寄存器。存储器的地址以一个寄存器的立即数偏移(immediate offset)指明。
指令格式:
op rd, rn,#immed_5×4]
oph rd, rn,#immed_5×2]
opb rd, rn,#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
1、thumb指令继承了arm指令集的许多特点 thumb指令也是采用load/store结构,有数据处理、数据传送及流控制指令等。
2、thumb指令集丢弃了arm指令集一些特性 大多数thumb指令是无条件执行的(除了转移指令b),而所有arm指令都是条件执行的。许多thumb数据处理指令采用2地址格式,即目的寄存器与一个源寄存器相同,而大多数arm数据处理指令采用的是3地址格式(除了64位乘法指令外)。
3、thumb异常时表现的一些特点 所有异常都会使微处理器返回到arm模式状态,并在arm的编程模式中处理。由于arm微处理器字传送地址必须可被4整除(即字对准),半字传送地址必须可被2整除(即半字对准)。而thumb指令是2个字节长,而不是4个字节,所以,由thumb执行状态进入异常时其自然偏移与arm不同。
1、在任何时刻,cpsr的第5位(位t)决定了arm微处理器执行的是arm指令流还是thumb指令流。当t置1,则认为是16位的thumb指令流;当t置0,则认为是32位的arm指令流。
2、进入thumb模式
3、进入thumb指令模式有两种方法:一种是执行一条交换转移指令bx,另一种方法是利用异常返回,也可以把微处理器从arm模式转换为thumb模式。
4、 退出thumb模式 退出thumb指令模式也有两种方法:一种是执行thumb指令中的交换转移bx指令可以显式的返回到arm指令流。另一种是利用异常进入arm指令流 。
thumb数据处理指令包括一组高度优化且相当复杂的指令,范围涵盖编译器通常需要的大多数操作。arm指令支持在单条指令中完成一个操作数的移位及一个alu操作,但thumb指令集将移位操作和alu操作分离为不同的指令。本部分从以下几个方面介绍: 数据处理指令的二进制编码 数据处理指令的分类 arm指令与thumb指令比较 数据处理指令的二进制编码如下所示:
按照数据处理指令的功能,可以将其分为以下几类:
add与sub—低寄存器加法和减法
add—高或低寄存器
add与sub—sp
add—pc或sp相对偏移
adc,sbc和mul
arm指令与thumb指令低寄存器比较:
arm指令与thumb指令高寄存器比较: