Thumb指令

更新时间: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指令高寄存器比较:

免责声明
隐私政策
用户协议
目录 22
0{{catalogNumber[index]}}. {{item.title}}
{{item.title}}