|  | 
 
| 11.4  Thumb数据处理指令 
 数据处理指令是指那些操作寄存器中数据的指令。Thumb指令集中的数据处理指令是ARM指令集数据处理指令的一个子集,其中包括MOV指令、算术指令、移位指令、逻辑指令、比较指令和乘法指令。表11.3列出了Thumb数据处理指令。
 
 表11.3 Thumb状态数据处理指令
 
 | 助  记  符 
 | 说    明 
 | 操    作 
 |  | ADC  Rd,Rm 
 | 带进位的32位加 
 | Rd:=Rd+Rm+C flag 
 |  | ADD  Rd,Rn,Rm 
 | 32位加 
 | Rd:=Rn+Rm 
 |  | ADD  Rd,Rn,#0~#7 
 | 32位加 
 | Rd:=Rn+3_bit_immed 
 |  | ADD  Rd,#0~#277 
 | 32位加 
 | Rd:=Rn+8_bit_immed 
 |  | AND  Rd,Rm 
 | 逻辑与 
 | Rd:=Rd AND Rm 
 |  | ASR  Rd,Rm,#1~#32 
 | 算术右移 
 | Rd:=Rm ASR 5_bit_immed 
 |  | ASR  Rd,Rs 
 | 算术右移 
 | Rd:=Rm ASR Rs 
 |  | BIC  Rd,Rm 
 | 位清零 
 | Rd:=Rd AND NOT Rm 
 |  | CMN  Rn,Rm 
 | 32位取负比较 
 | Rn+Rm 并设置标志位 
 |  | CMP  Rn,#0~#255 
 | 32位整数比较 
 | Rn-8_bit_immed 并设置标志位 
 |  | CMP  Rn,Rm 
 | 32位整数比较 
 | Rn-Rm 并设置标志位 
 |  | EOR  Rd,Rm 
 | 异或 
 | Rd:=Rd EOR Rm 
 |  | LSL  Rd,Rm,#0~#31 
 | 逻辑左移 
 | Rd:=Rm LSL 5_bit_immed 
 |  | LSL  Rd,Rs 
 | 逻辑左移 
 | Rd:=Rd LSL Rs 
 |  | LSR  Rd,Rm,#1~#32 
 | 逻辑右移 
 | Rd:=Rm LSR 5_bit_immed 
 |  | LSR  Rd,Rs 
 | 逻辑右移 
 | Rd:=Rd LSR Rs 
 |  | MOV  Rd,#0~#255 
 | 将数据送入寄存器 
 | Rd:=8_bit_immed 
 |  | MOV  Rd,Rn 
 | 将数据送入寄存器 
 | Rd:=Rn 
 |  | MUL  Rd,Rm 
 | 乘 
 | Rd:=Rm*Rd 
 |  | MVN  Rd,Rm 
 | 将32位数的“反”送入寄存器 
 | Rd:=NOT Rm 
 |  | NEG  Rd,Rm 
 | 求反 
 | Rd:=0-Rm 
 |  | ORR  Rd,Rm 
 | 逻辑或 
 | Rd:=Rd OR Rm 
 |  | ROR  Rd,Rs 
 | 逻辑右移 
 | Rd:=Rd ROR Rs 
 |  | SBC  Rd,Rm 
 | 带进位减 
 | Rd:=Rd-Rm-NOT(Carry Flag) 
 |  | SUB  Rd,Rn,Rm 
 | 减 
 | Rd:=Rn-Rm 
 |  | SUB  Rd,Rn,#0~#7 
 | 减 
 | Rd:=Rn-3_bit_immed 
 |  | SUB  Rd,#0~#255 
 | 减 
 | Rd:=Rn-8_bit_immed 
 |  | TST  Rn,Rm 
 | 位测试指令 
 | Rn AND Rm 并更新标志位 
 | 
 Thumb的数据处理指令与等价的ARM指令使用相同的格式。所有对r0~r7低8个寄存器操作的数据处理指令都更新条件标志位,对r8~r14和PC高8个寄存器操作的指令除MOV指令外,其他指令均不改变条件标志位。这些指令包括:
 
 ·  MOV  Rd,Rn
 ·  ADD  Rd,Rm
 ·  CMP  Rn,Rm
 ·  ADD  sp,#0~#508
 ·  SUB  sp,#0~#508
 ·  ADD  Rd,sp,#0~#1020
 ·  ADD  Rd,pc,#0~#1020
 
 Thumb数据处理指令的基本语法格式分为以下8种。
 
 ① <opcode1>  <Rd>,<Rn>,<Rm>
 <opcode1>:=ADD|SUB
 ② <opcode2>  <Rd>,<Rn>,#<3_bit_immed>
 <opcode2>:=ADD|SUB
 ③ <opcode3>  <Rd>|<Rn>,#<8_bit_immed>
 <opcode3>:=ADD|SUB|MOV|CMP
 ④ <opcode4>  <Rd>,<Rm>,#<shift_immed>
 <opcode4>:=LSL|LSR|ASR
 ⑤ <opcode5>  <Rd>|<Rn>,<Rm>|<Rs>
 <opcode5>:=MVN|CMP|CMN|TST|ADC|SBC|NEG|MUL|LSL|LSR|ASR|ROR|AND|EOR|BIC
 ⑥ ADD  <Rd>,<reg>,#<8_bit_immed>
 <reg>:=SP|PC
 ⑦ <opcode6>  SP,SP,#<7_bit_immed>
 <opcode6>:=ADD|SUB
 ⑧ <opcode7>  <Rd>|<Rn>,<Rm>
 <opcode7>:=MOV|ADD|CMP
 
 
 |   
 | 注意 
 | 上面的指令和语法格式中,3_bit_immed、7_bit_immed、8_bit_immed分别表示3位、7位、8位立即数。 
 | 
 下面详细介绍各指令的语法和使用。
 
 11.4.1  ADC指令
 
 (1)编码格式
 带进位的加法指令ADC的编码格式如图11.7所示。
 
 
         图11.7  ADC指令的编码格式 
 带进位的ADC指令和加法指令ADD配合使用可以实现多字相加(multi-word),详见ARM指令集介绍。
 
 (2)指令的语法格式
 
 ADC  <Rd>,<Rm>
 
 ① <Rd>
 第一个操作数寄存器,并且是操作结果的目的寄存器。
 ② <Rm>
 第二操作数寄存器。
 
 (3)指令操作的伪代码
 
 Rd = Rd+Rm+C Flag
 N Flag = Rd[31]
 Z Flag = if Rd==0 then 1 else 0
 C Flag = CarryFrom{Rd+Rm+C Flag}
 V Flag = OverflowFrom{Rd+Rm+C Flag}
 (4)对应的ARM指令
 
 ADCS  <Rd>,<Rd>,<Rm>
 
 11.4.2  小立即数加法指令ADD(1)
 
 (1)编码格式
 立即数加法指令ADD(1)的编码格式如图11.8所示。
 
 
         图11.8  ADD(1)指令的编码格式 
 ADD加法指令实现“小常数”的加法运算,并将相加的结果保存到指定的寄存器中。
 
 (2)指令的语法格式
 
 ADD  <Rd>,<Rn>,#<immed_3>
 
 ① <Rd>
 加法操作的目标寄存器。
 ② <Rn>
 操作数寄存器。
 ③ #<immed_3>
 3位的立即数。该立即数将和寄存器<Rn>的值相加,并将结果保存到<Rd>中。
 
 (3)指令操作的伪代码
 
 Rd = Rn+immed_3
 N Flag = Rd[31]
 Z Flag = if Rd==0 then 1 else 0
 C Flag = CarryFrom{Rn+ immed_3}
 V Flag = OverflowFrom{Rn+ immed_3}
 
 (4)对应的ARM指令
 
 ADDS  <Rd>,<Rn>,#<immed_3>
 
 11.4.3  大立即数加法指令ADD(2)
 
 (1)编码格式
 立即数加法指令ADD(2)的编码格式如图11.9所示。
 
 
         图11.9  ADD(2)指令的编码格式 
 此中形式的ADD(2)指令将一个大的立即数(8 bit)与指定寄存器的值相加,并将运算结果保存到此寄存器中。
 
 (2)指令的语法格式
 
 ADD  <Rd>,#<immed_8>
 
 ① <Rd>
 加法操作的目标寄存器。
 ② #<immed_8>
 8位的立即数。该立即数将和寄存器<Rd>的值相加,并将结果保存到<Rd>中。
 
 (3)指令操作的伪代码
 
 Rd = Rd+immed_8
 N Flag = Rd[31]
 Z Flag = if Rd==0 then 1 else 0
 C Flag = CarryFrom{Rn+ immed_8}
 V Flag = OverflowFrom{Rn+ immed_8}
 
 (4)对应的ARM指令
 
 ADDS  <Rd>,<Rd>,#<immed_8>
 
 11.4.4  寄存器加法指令ADD(3)
 
 (1)编码格式
 寄存器加法指令ADD(3)的编码格式如图11.10所示。
 
 
         图11.10  ADD(3)指令的编码格式 
 此种形式的加法指令将两个寄存器的值相加,将结果放入第三个目标寄存器,并根据操作结果更新标志位。
 
 (2)指令的语法格式
 
 ADD  <Rd>,<Rn>,<Rm>
 
 ① <Rd>
 加法操作的目标寄存器。
 ② <Rn>
 操作数寄存器。存放加法操作的第一个操作数。
 ③ <Rm>
 操作数寄存器。存放加法操作的第二个操作数。
 
 (3)指令操作的伪代码
 
 Rd=Rn+Rm
 N Flag = Rd[31]
 Z Flag = if Rd = =0 then 1 else 0
 C Flag = CarryFrom(Rn+Rm)
 V Flag = OverflowFrom(Rn+Rm)
 
 11.4.5  寄存器加法指令ADD(4)
 
 (1)编码格式
 寄存器加法指令ADD(4)的编码格式如图11.11所示。
 
 
         图11.11  ADD(4)指令的编码格式 
 此种形式的加法指令将两个寄存器的值相加,将结果放入第三个目标寄存器。该指令不更新程序状态字的标志位。
 
 
 | ![]() 
 | 注意 
 | 该指令与ADD(3)的区别在于其操作数寄存器。该指令的操作数寄存器为r8~r14和PC高寄存器。操作结果对程序状态字的标志位没有影响。 
 | 
 (2)指令的语法格式
 
 ADD  <Rd>,<Rm>
 
 ① <Rd>
 指令的操作数寄存器,其中保存加法操作的一个操作数,并将指令的操作结果放入该寄存器。取值范围为r0~r15。
 ② <Rm>
 操作数寄存器。存放加法操作的第二个操作数。可以为r0~r15的任意寄存器。
 
 (3)指令操作的伪代码
 
 Rd = Rd+Rm
 
 11.4.6  PC相关加法指令ADD(5)
 
 (1)编码格式
 寄存器加法指令ADD(5)的编码格式如图11.12所示。
 
 
         图11.12  ADD(5)指令的编码格式 
 该指令将一个立即数和PC值相加,并将PC相关地址写入目标寄存器。立即数可以是0~1020范围内的任意数值的4倍。该指令不更新程序状态字的标志位。
 
 (2)指令的语法格式
 
 ADD  <Rd>,PC,#<immed_8>×4
 
 ① <Rd>
 指令的目的寄存器,存放指令的操作结果。
 ② PC
 PC相关地址。
 ③ <immed_8>
 加到PC值上的8位立即数。
 
 (3)指令操作的伪代码
 
 Rd=(PC AND 0xfffffffc)+(immed_8<<2)
 
 11.4.7  SP相关加法指令ADD(6)
 
 (1)编码格式
 寄存器加法指令ADD(6)的编码格式如图11.13所示。
 
 
         图11.13  ADD(6)指令的编码格式 
 该指令将一个立即数和SP值相加,并将SP相关地址写入目标寄存器。立即数可以是0~1020范围内的任意4的倍数。该指令不更新程序状态字的标志位。
 
 (2)指令的语法格式
 
 ADD  <Rd>,SP,#<immed_8>×4
 
 ① <Rd>
 指令的目的寄存器,存放指令的操作结果。
 ② SP
 SP相关地址。
 ③ <immed_8>
 该立即数的4倍将与SP值相加。
 
 (3)指令操作的伪代码
 
 Rd=SP+(immed_8<<2)
 
 11.4.8  SP相关加法指令ADD(7)
 
 (1)编码格式
 寄存器加法指令ADD(6)的编码格式如图11.14所示。
 该指令将一个立即数和SP值相加,并将SP相关地址写回SP寄存器。立即数可以是0~508范围内的任意数值的4倍。该指令不更新程序状态字的标志位。
 
 
         图11.14  ADD(7)指令的编码格式 
 (2)指令的语法格式
 
 ADD  SP,#<immed_7>×4
 
 ① SP
 SP相关地址,同时也为指令的目标寄存器。
 ② <immed_7>
 指定的7位立即数,该立即数的4倍将与SP值相加。
 
 11.4.9  逻辑与指令AND
 
 (1)编码格式
 逻辑与指令AND的编码格式如图11.15所示。
 
 
         图11.15  AND指令的编码格式 
 AND指令实现两个寄存器值的按位“与”操作。程序状态字的标志位根据指令的执行结果更新。
 
 (2)指令的语法格式
 
 AND  <Rd>,<Rm>
 
 ① <Rd>
 操作数寄存器,包含指令的第一个操作数。同时也为指令操作结果的目的寄存器。
 ② <Rm>
 操作数寄存器,保护指令的第二个操作数。
 
 (3)指令操作的伪代码
 
 Rd = Rd AND Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 ANDS  <Rd>,<Rd>,<Rm>
 
 11.4.10  算术右移指令ASR(1)
 
 (1)编码格式
 算术右移指令ASR(1)的编码格式如图11.16所示。
 
 
         图11.16  ASR(1)指令的编码格式 
 这种形式的算术右移指令可以方便的实现将一个寄存器的值除以一个常数。该常数是以2为底的幂。
 
 (2)指令的语法格式
 
 ASR  <Rd>,<Rm>,#<immed_5>
 
 ① <Rd>
 目的寄存器。用于存放指令操作的结果。
 ② <Rm>
 操作数寄存器。存放将要被右移的数据。
 ③ <immed_5>
 指定右移的位数。该常数取值范围为1~31。
 
 (3)指令操作的伪代码
 
 If  immed_5 == 0
 C Flag = Rm[31]
 If Rm[31] = =0 then
 Rd = 0
 Else /*Rm[31] = =1*/
 Rd = 0xffffffff
 Else /*immed_5 > 0*/
 C Flag = Rm[immed_5-1]
 Rd = Rm Arithmetic_shift_Right immed_5
 N Flag = Rd[31]
 Z Flag = if Rd = =0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rm>,ASR#<immed_5>
 
 
 | ![]() 
 | 注意 
 | 在ARMv5以前的体系结构版本中,没有单独的Thumb移位指令。在ARMv6版本中已经增加了位移指令,详细信息请参加ARM体系结构相关文档。 
 | 
 
 11.4.11  算术右移指令ASR(2)
 
 (1)编码格式
 算术右移指令ASR(2)的编码格式如图11.17所示。
 
 
         图11.17  ASR(2)指令的编码格式 
 此种形式的ASR指令的操作数均为寄存器。该指令根据指令的操作结果更新程序状态字的标志位。
 
 (2)指令的语法格式
 
 ASR  <Rd>,<Rs>
 
 ① <Rd>
 存放指令的操作数和操作结果。
 ② <Rs>
 指定操作数将要被移动的位数。
 
 (3)指令操作的伪代码
 
 If  Rs[7:0] = = 0 then
 C Flag = unaffected
 Rd = unaffected
 Else if Rs[7:0] < 32 then
 C Flag = Rd[Rs[7:0] - 1]
 Rd = Rd arithmetic_shift_Right Rs[7:0]
 Else /*Rs[7:0] >= 32*/
 C Flag = Rd[31]
 If Rd[31] = = 0 then
 Rd = 0
 Else /*Rd[31] = = 1*/
 Rd = 0xffffffff
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rd>,ASR<Rs>
 
 11.4.12  位清零指令BIC
 
 (1)编码格式
 位清零指令BIC的编码格式如图11.18所示。
 
 
         图11.18  BIC指令的编码格式 
 BIC指令将两个寄存器的值按位做“异或”操作。该指令根据指令的执行结果更新程序状态字的标志位。
 
 (2)指令的语法格式
 
 BIC  <Rd>,<Rm>
 
 ① <Rd>
 存放指令的操作数和操作结果。
 ② <Rm>
 操作数寄存器,该寄存器中的数据的反码将会和<Rd>中的值做“与”操作。
 
 (3)指令操作的伪代码
 
 Rd = Rd AND NOT Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 BICS  <Rd>,<Rd>,<Rm>
 
 11.4.13  比较指令CMN
 
 (1)编码格式
 比较指令CMN的编码格式如图11.19所示。
 
 
         图11.19  CMN指令的编码格式 
 比较指令CMN将一个寄存器的值和另一个寄存器的值取负做比较,并根据比较结果更新程序状态字的标志位。程序中比较指令后通常跟条件执行指令。
 
 (2)指令的语法格式
 
 CMN  <Rn>,<Rm>
 
 ① <Rn>
 操作数寄存器。用于存放指令的第一个操作数。
 ② <Rm>
 操作数寄存器。用于存放指令的第二个操作数。
 
 (3)指令操作的伪代码
 
 Alu_out = Rn + Rm
 N Flag = alu_out[31]
 Z Flag = if alu_out = = 0 then 1 else 0
 C Flag = NOT BorrowFrom(Rn + Rm)
 V Flag = OverflowFrom(Rn+Rm)
 
 (4)对应的ARM指令
 
 CMN  <Rn>,<Rm>
 
 11.4.14  比较指令CMP(1)
 
 (1)编码格式
 比较指令CMP(1)的编码格式如图11.20所示。
 
 
         图11.20  CMP(1)指令的编码格式 
 比较指令CMP(1)将一个寄存器的值和8位立即数做比较,并根据比较结果更新程序状态字的标志位。程序中比较指令后通常跟条件执行指令。
 
 (2)指令的语法格式
 
 CMP  <Rn>,#<immed_8>
 
 ① <Rn>
 操作数寄存器。
 ② <immed_8>
 8位常数。将与寄存器<Rn>的值做比较。
 
 (3)指令操作的伪代码
 
 Alu_out = Rn – immed_8
 N Flag = alu_out[31]
 Z Flag = if alu_out == 0 then 1 else 0
 C Flag = NOT BorrowFrom(Rn – immed_8)
 V Flag = OverflowFrom(Rn – immed_8)
 
 (4)对应的ARM指令
 
 CMP  <Rn>,#<immed_8>
 
 11.4.15  比较指令CMP(2)
 
 (1)编码格式
 比较指令CMP(2)的编码格式如图11.21所示。
 
 
         图11.21  CMP(2)指令的编码格式 
 比较指令CMP(2)将两个寄存器的值做比较,并根据比较结果更新程序状态字的标志位。程序中比较指令后通常跟条件执行指令。
 
 (2)指令的语法格式
 
 CMP  <Rn>,<Rm>
 
 ① <Rn>
 操作数寄存器,存放比较的第一个操作数。
 ② <Rm>
 操作数寄存器,存放比较的第二个操作数。
 
 (3)指令操作的伪代码
 
 alu_out = Rn – Rm
 N Flag = alu_out[31]
 Z Flag = if alu_out = = 0 then 1 else 0
 C Flag = NOT BorrowFrom(Rn - Rm)
 V Flag = OverflowFrom(Rn - Rm)
 
 (4)对应的ARM指令
 
 CMP  <Rn>,<Rm>
 
 11.4.16  比较指令CMP(3)
 
 (1)编码格式
 比较指令CMP(3)的编码格式如图11.22所示。
 
 
         图11.22  CMP(3)指令的编码格式 
 比较指令CMP(3)将两个寄存器的值做比较,其中一个寄存器为r8~r14或PC寄存器高16位。并根据比较结果更新程序状态寄存器的标志位。程序中比较指令后通常跟条件执行指令,实现指令的分支跳转。
 
 (2)指令的语法格式
 
 CMP  <Rn>,<Rm>
 
 ① <Rn>
 操作数寄存器。保存将要进行比较的第一个操作数,其取值可以为r0~r15的任意寄存器。
 ② <Rm>
 操作数寄存器。保存将要进行比较的第二个操作数,其取值可以为r0~r15的任意寄存器。
 
 (3)指令操作的伪代码
 
 alu_out = Rn – Rm
 N Flag = alu_out[31]
 Z Flag = if alu_out = = 0 then 1 else 0
 C Flag = NOT BorrowFrom(Rn - Rm)
 V Flag = OverflowFrom (Rn - Rm)
 
 
 | ![]() 
 | 注意 
 | 指令操作数寄存器<Rn>和<Rm>中,至少有一个寄存器为r8~r14或PC寄存器的高16位,否则,指令的执行结果不可预知。 
 | 
 (4)对应的ARM指令
 
 CMP  <Rn>,<Rm>
 
 11.4.17  异或指令EOR
 
 (1)编码格式
 比较指令EOR的编码格式如图11.23所示。
 
 
         图11.23  EOR指令的编码格式 
 EOR指令将两个寄存器中的数值按位执行“异或”操作,并根据指令的执行结果更新程序状态寄存器的标志位。
 
 (2)指令的语法格式
 
 EOR  <Rn>,<Rm>
 
 ① <Rn>
 操作数寄存器。同时保存指令的第一个操作数和指令的执行结果。
 ② <Rm>
 操作数寄存器。保存将要进行比较的第二个操作数。
 
 (3)指令操作的伪代码
 
 Rd = Rd OR Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 EORS  <Rd>,<Rd>,<Rm>
 
 11.4.18  逻辑左移指令LSL(1)
 
 (1)编码格式
 逻辑左移指令LSL(1)的编码格式如图11.24所示。
 
 
         图11.24  LSL(1)指令的编码格式 
 逻辑左移指令LSL(1)可以实现以2为底的幂的乘法。进行移位后空出的位添0。
 
 (2)指令的语法格式
 
 LSL  <Rd>,<Rm>,#<immed_5>
 
 ① <Rd>
 目的寄存器。存储指令的操作结果。
 ② <Rm>
 操作数寄存器。该寄存器保存的数据将进行左移操作。
 ③ <immed_5>
 逻辑左移位数,范围为0~31。
 
 (3)指令操作的伪代码
 
 if  immed_5 = = 0
 C Flag = unaffected
 Rd = Rm
 Else  /*immed_5 > 0*/
 C Flag =Rm[32 – immed_5]
 Rd = Rm logical_shift_left immed_5
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rm>,LSL#<immed_5>
 
 11.4.19  逻辑左移指令LSL(2)
 
 (1)编码格式
 逻辑左移指令LSL(2)的编码格式如图11.25所示。
 
 
         图11.25  LSL(2)指令的编码格式 
 逻辑左移指令LSL(2)可以实现以2为底的幂的乘法。进行移位后空出的位添0并根据指令的操作结果更新程序状态寄存器的标志位。
 
 (2)指令的语法格式
 
 LSL  <Rd>,<Rs>
 
 ① <Rd>
 操作数寄存器,包含被移位的值并保存指令的执行结果。
 ② <Rs>
 包含逻辑左移位数的寄存器。
 
 (3)指令操作的伪代码
 
 if  Rs[7:0] = = 0
 C Flag = unaffected
 Rd = unaffected
 Else  if  Rs[7:0] < 32 then
 C Flag = Rd[32 – Rs[7:0]]
 Rd = Rd logical_shift_left  Rs[7:0]
 Else  if  Rs[7:0] = = 32 then
 C Flag = Rd[0]
 Rd = 0
 Else  if  Rs[7:0] = = 32 then
 C Flag = Rd[0]
 Rd = 0
 Else  /*Rs[7:0] > 32*/
 C Flag = 0
 Rd = 0
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rd>,LSL<Rs>
 
 11.4.20  逻辑右移指令LSR(1)
 
 (1)编码格式
 逻辑左移指令LSR(1)的编码格式如图11.26所示。
 
 
         图11.26  LSR(1)指令的编码格式 
 逻辑右移指令LSR(1)可以实现以2为底的幂做除数的除法。进行移位后空出的位添0,并根据指令的执行结果更新程序状态寄存器的标志位。
 
 (2)指令的语法格式
 
 LSR  <Rd>,<Rm>,#<immed_5>
 
 ① <Rd>
 目的寄存器。存储指令的操作结果。
 ② <Rm>
 操作数寄存器。该寄存器保存的数据将进行右移操作。
 ③ <immed_5>
 逻辑右移位数,范围为0~31。
 
 (3)指令操作的伪代码
 
 if  immed_5 = = 0
 C Flag = Rd[31]
 Rd = 0
 Else /*immed_5>0*/
 C Flag = Rd[immed_5 - 1]
 Rd = Rm Logial_shift_right immed_5
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rm>,LSR#<immed_5>
 
 11.4.21  逻辑右移指令LSR(2)
 
 (1)编码格式
 逻辑左移指令LSR(2)的编码格式如图11.27所示。
 
 
         图11.27  LSR(2)指令的编码格式 
 逻辑右移指令LSR(2)可以实现以2为底的幂做除数的无符号除法。进行移位后空出的位添0,并根据指令的操作结果更新程序状态寄存器的标志位。
 (2)指令的语法格式
 
 LSR  <Rd>,<Rs>
 
 ① <Rd>
 操作数寄存器,包含被移位的值并保存指令的执行结果。
 ② <Rs>
 包含逻辑右移位数的寄存器。
 (3)指令操作的伪代码
 
 if  Rs[7:0] = = 0
 C Flag = unaffected
 Rd = unaffected
 Else  if  Rs[7:0] < 32 then
 C Flag = Rd[Rs[7:0] - 1]
 Rd = Rd logical_shift_Right  Rs[7:0]
 Else  if  Rs[7:0] = = 32 then
 C Flag = Rd[31]
 Rd = 0
 Else  if  Rs[7:0] = = 32 then
 C Flag = Rd[0]
 Rd = 0
 Else  /*Rs[7:0] > 32*/
 C Flag = 0
 Rd = 0
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rd>,LSR<Rs>
 
 11.4.22  移位指令MOV(1)
 
 (1)编码格式
 数据传送指令MOV(1)的编码格式如图11.28所示。
 
 
         图11.28  MOV(1)指令的编码格式 
 (2)指令的语法格式
 
 MOV  <Rd>,#<immed_8>
 ① <Rd>
 目的寄存器。存放指令的执行结果。
 ② <immed_8>
 8位立即数。指示要移入寄存器的数据。
 
 (3)指令操作的伪代码
 
 Rd = immed_8
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,#<immed_8>
 
 11.4.23  移位指令MOV(2)
 
 (1)编码格式
 数据传送指令MOV(2)的编码格式如图11.29所示。
 
 
         图11.29  MOV(2)指令的编码格式 
 此种形式的MOV指令用于数据在r0~r7低寄存器间传送,并根据的指令的执行结果更新程序状态寄存器的标志位。
 
 
 | ![]() 
 | 注意 
 | 从指令的编码形式可以看出,MOV(2)指令被作为ADD  Rd,Rn,#0指令来编译。 
 | 
 (2)指令的语法格式
 
 MOV  <Rd>,<Rn>
 
 ① <Rd>
 目的寄存器。存放指令的执行结果。
 ② <Rn>
 源寄存器。用于存放被传送的数据。
 
 (3)指令操作的伪代码
 
 Rd = Rn
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = 0
 V Flag = 0
 
 (4)对应的ARM指令
 
 ADD  <Rd>,<Rn>,#0
 
 11.4.24  移位指令MOV(3)
 
 (1)编码格式
 数据传送指令MOV(3)的编码格式如图11.30所示。
 
 
         图11.30  MOV(3)指令的编码格式 
 此种形式的MOV指令用于在r8~r14和PC寄存器的高16位内传送数据。与MOV(2)指令不同,该指令不影响程序状态寄存器。
 
 (2)指令的语法格式
 
 MOV  <Rd>,<Rm>
 
 ① <Rd>
 目的寄存器。可以是r0~r15中的任意寄存器,用于存放指令的执行结果。
 ② <Rm>
 源寄存器。可以是r0~r15中的任意寄存器,用于存放被传输的数据。
 
 (3)指令操作的伪代码
 
 Rd = Rm
 
 (4)指令的使用
 可以使用此种形式的MOV指令MOV  PC,r14用于子程序的返回(返回的程序是Thumb子程序)。它和BX指令的区别在于BX指令可以用于ARM和Thumb程序间的相互调用。
 
 
 | ![]() 
 | 注意 
 | 如果目的寄存器<Rd>和源寄存器<Rm>同时为r0~r7低寄存器,则指令的执行结果不可预知。 
 | 
 (5)对应的ARM指令
 
 MOV  <Rd>,<Rm>
 
 11.4.25  乘法指令MUL
 
 (1)编码格式
 乘法指令MUL的编码格式如图11.31所示。
 
 
         图11.31  MUL指令的编码格式 
 MUL指令实现两个数(可以为无符号数,也可以为有符号数)的乘积,并将指令的执行结果存放到一个32位的寄存器中,同时可以根据运算结果设置CPSR寄存器中相应的条件标志位。
 (2)指令的语法格式
 
 MUL  <Rd>,<Rm>
 
 ① <Rd>
 目的寄存器,存放乘法操作的第一个乘数。
 ② <Rm>
 第二个乘数所在寄存器。
 
 (3)指令操作的伪代码
 
 Rd = (Rm * Rd)[31:0]
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 
 | ![]() 
 | 注意 
 | 如果乘法指令MUL的源和目的寄存器使用相同的寄存器,则指令的执行结果不可预知;对于有符号数和无符号数,指令的操作结果是一样的。 
 | 
 (4)对应的ARM指令
 
 MULS  <Rd>,<Rm>,<Rd>
 
 11.4.26  传送指令MVN
 
 (1)编码格式
 传送指令MVN的编码格式如图11.32所示。
 
 
         图11.32  MVN指令的编码格式 
 MVN指令将一个数的反码传送到目标寄存器,并根据指令的执行结果更新CPSR中相应的条件标志位。
 
 (2)指令的语法格式
 
 MVN  <Rd>,<Rm>
 
 ① <Rd>
 目的寄存器,存放指令的操作结果。
 ② <Rm>
 源寄存器,存放要传送反码的数据。
 
 (3)指令操作的伪代码
 
 Rd = NOT Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MVNS  <Rd>,<Rm>
 
 11.4.27  取反指令NEG
 
 (1)编码格式
 取反指令NEG的编码格式如图11.33所示。
 
 
         图11.33  NEG指令的编码格式 
 NEG取反指令将一个寄存器的值取反存入另一个寄存器。同时根据指令的操作结果更新CPSR中相应的条件标志位。
 
 (2)指令的语法格式
 
 NEG  <Rd>,<Rm>
 
 ① <Rd>
 目的寄存器,存放指令的操作结果。
 ② <Rm>
 源寄存器,包含将要被取反的数据。
 
 (3)指令操作的伪代码
 
 Rd = 0 – Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = NOT BorrowFrom(0 - Rm)
 V Flag = OverflowFrom(0 - Rm)
 
 (4)对应的ARM指令
 
 RSBS  <Rd>,<Rm>,#0
 
 11.4.28  逻辑或指令ORR
 
 (1)编码格式
 逻辑或指令ORR的编码格式如图11.34所示。
 
 
         图11.34  ORR指令的编码格式 
 ORR指令将两个寄存器的值做按位做或运算,并根据指令的执行结果更新程序状态寄存器的标志位。
 
 (2)指令的语法格式
 
 ORR  <Rd>,<Rm>
 
 ① <Rd>
 目的寄存器,存放指令的操作结果,存放做逻辑或运算的其中一个操作数。
 ② <Rm>
 存放做逻辑或运算的另一个操作数。
 
 (3)指令操作的伪代码
 
 Rd = Rd OR Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 ORRS  <Rd>,<Rd>,<Rm>
 
 11.4.29  循环右移指令ROR
 
 (1)编码格式
 循环右移指令ROR的编码格式如图11.35所示。
 
 
         图11.35  ROR指令的编码格式 
 ROR指令将一个给定寄存器的值循环右移一定的位数。并根据指令的操作结果更新状态寄存器的条件标志位。详见指令操作伪代码。
 
 (2)指令的语法格式
 
 ROR  <Rd>,<Rs>
 
 ① <Rd>
 目的寄存器。存储指令的操作结果和被移位的数值。
 ② <Rs>
 循环左移的位数。
 
 (3)指令操作的伪代码
 
 if  Rs[7:0] = = 0 then
 C Flag = unaffected
 Rd = unaffected
 Else if Rs[4:0] = = 0 then
 C Flag = Rd[31]
 Rd = unaffected
 Else /*Rs[4:0] > 0 */
 C Flag = Rd[Rs[4:0]- 1 ]
 Rd = Rd Rotate_Right Rs[4:0]
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 MOVS  <Rd>,<Rd>,ROR<Rs>
 
 11.4.30  带进位的减指令SBC
 
 (1)编码格式
 带进位的减指令SBC的编码格式如图11.36所示。
 
 
         图11.36  SBC指令的编码格式 
 SBC指令从指定寄存器中减去另一个寄存器的数值,再减去寄存器CPSR中C条件标志位的反码,并把结果保存到目标寄存器中,同时根据操作的结果更新CPSR中相应的条件标志位。
 
 (2)指令的语法格式
 
 SBC  <Rd>,<Rm>
 
 ① <Rd>
 被减数寄存器,同时保存指令的操作结果。
 ② <Rm>
 减数寄存器,保存减法操作的减数。
 
 (3)指令操作的伪代码
 
 Rd = Rd – Rm – NOT(C Flag)
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = NOT BorrowFrom(Rd – Rm – NOT(C Flag))
 V Flag = Overflow From(Rd – Rm – NOT(C Flag))
 
 (4)对应的ARM指令
 
 SBCS  <Rd>,<Rd>,<Rm>
 
 11.4.31  减法指令SUB(1)
 
 (1)编码格式
 减法指令SUB(1)的编码格式如图11.37所示。
 
 
         图11.37  SUB(1)指令的编码格式 
 SUB(1)指令从指定寄存器减去3位立即数(取值范围为0~8),并把指令的操作结果保存到寄存器,同时根据结果更新CPSR中相应的条件标志位。
 
 (2)指令的语法格式
 
 SUB  <Rd>,<Rn>,#<immed_3>
 
 ① <Rd>
 目的寄存器,存放指令的操作结果。
 ② <Rn>
 被减数寄存器,包含减法操作的被减数。
 ③ <immed_3>
 作为减数的立即数,该立即数的取值范围为0~8。
 
 (3)指令操作的伪代码
 
 Rd = Rn – immed_3
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = NOT BorrowFrom (Rn – immed_3)
 V Flag = OverflowFrom(Rn – immed_3)
 
 (4)对应的ARM指令
 
 SUBS  <Rd>,<Rn>,#<immed_3>
 
 11.4.32  减法指令SUB(2)
 
 (1)编码格式
 减法指令SUB(2)的编码格式如图11.38所示。
 SUB(2)指令从指定寄存器减去8位立即数(即,取值范围为0~256),并把指令的操作结果保存到寄存器,同时根据结果更新CPSR中相应的条件标志位。
 
 
         图11.38  SUB(2)指令的编码格式 
 (2)指令的语法格式
 
 SUB  <Rd>,#<immed_8>
 
 ① <Rd>
 第一个源操作数所在的寄存器,存放减法操作的被减数,同时将减法操作的执行结果保存到该寄存器。
 ② <immed_8>
 8位立即数,即减法操作的减数,取值范围为0~255。
 
 (3)指令操作的伪代码
 
 Rd = Rd – immed_8
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = NOT BorrowFrom (Rn – immed_8)
 V Flag = OverflowFrom(Rn – immed_8)
 
 (4)对应的ARM指令
 
 SUBS  <Rd>,<Rd>,#<immed_8>
 
 11.4.33  减法指令SUB(3)
 
 (1)编码格式
 减法指令SUB(3)的编码格式如图11.39所示。
 
 
         图11.39  SUB(3)指令的编码格式 
 SUB(3)指令将指定寄存器的值和另一个寄存器表示的值做减法运算,并根据指令的操作结果更新状态寄存器的标志位。
 
 (2)指令的语法格式
 
 SUB  <Rd>,<Rn>,<Rm>
 
 ① <Rd>
 目的寄存器,存放指令操作的结果。
 ② <Rn>
 源寄存器,存放第一个操作数,即减法运算的被减数。
 ③ <Rm>
 源寄存器,存放第二个操作数,即减法运算的减数。
 
 (3)指令操作的伪代码
 
 Rd = Rd – Rm
 N Flag = Rd[31]
 Z Flag = if Rd = = 0 then 1 else 0
 C Flag = NOT BorrowFrom (Rn –Rm)
 V Flag = OverflowFrom(Rn – Rm)
 
 (4)对应的ARM指令
 
 SUBS  <Rd>,<Rn>,<Rm>
 
 11.4.34  减法指令SUB(4)
 
 (1)编码格式
 减法指令SUB(4)的编码格式如图11.40所示。
 
 
         图11.40  SUB(4)指令的编码格式 
 SUB(4)指令从堆栈指针SP中减去7位立即数的4倍,也就是说其取值为在0~508范围内4的倍数。
 
 (2)指令的语法格式
 
 SUB  SP,#<immed_7>×4
 
 ① SP
 程序的堆栈指针,同时也为指令的目的寄存器,存放指令的运算结果。
 ② <immed_7>
 7位立即数,其值的4倍将作为减数参加运算。
 
 (3)指令操作的伪代码
 
 SP = SP – (immed_7 << 2)
 
 
 | ![]() 
 | 注意 
 | 在Thumb指令集中,使用满递减堆栈,该指令常被用于元素的入栈操作。 
 | 
 (4)对应的ARM指令
 
 SUB  SP,SP,#<immed_7>*4
 
 11.4.35  位测试指令TST
 
 (1)编码格式
 位测试指令TST的编码格式如图11.41所示。
 
 
         图11.41  TST指令的编码格式 
 TST指令将两个寄存器的值按位做逻辑与操作,并根据指令的执行结果更新CPSR中相应的条件标志位。TST指令常被用于测试寄存器中某一位是否置位。
 
 (2)指令的语法格式
 
 TST  <Rn>,<Rm>
 
 ① <Rn>
 操作数寄存器,用于存放指令的第一个操作数。
 ② <Rm>
 操作寄存器,该寄存器中的值将和<Rn>寄存器中的值做逻辑与操作。
 
 (3)指令操作的伪代码
 
 alu_out = Rn AND Rm
 N Flag = alu_out[31]
 Z Flag = if alu_out = = 0 then 1 else 0
 C Flag = unaffected
 V Flag = unaffected
 
 (4)对应的ARM指令
 
 TST  <Rn>,<Rm>
 
 11.4.36  Thumb指令集中数据操作指令举例
 
 下面的例子程序综合使用了各种数据操作指令,通过该例可以对Thumb状态下数据操作指令有更深入的了解。
 
 ADD  r0,r4,r7 ;r0 = r4 + r7
 SUB  r6,r1,r2 ;r6 = r1 – r2
 ADD  r0,#255 ;r0 = r0 + 255
 ADD  r1,r4,#4 ;r1 = r4 + 4
 NEG  r3,r1 ;r3 = 0 – r1
 ADD  r2,r5 ;r2 = r2 AND r5
 EOR  r1,r6 ;r1 = r1 EOR r6
 CMP  r2,r3 ;r2 – r3 ,并更新CPSR
 CMP  r7,#100 ;r7 – 100 ,并更新CPSR
 MOV  r0,#200 ;r0 = 200
 | 
 |