义网站建设推荐郑国华,网站开发要学什么语言,工程公司需要哪些资质证书,开发者模式影响手机吗一、ARM指令集 
ARM是RISC架构#xff0c;所有的指令长度都是32位#xff0c;并且大多数指令都在一个单周期内执行。主要特点#xff1a;指令是条件执行的#xff0c;内存访问使用Load/store架构。 二、Thumb 指令集 
Thumb是一个16位的指令集#xff0c;是ARM指令集的功能…一、ARM指令集 
ARM是RISC架构所有的指令长度都是32位并且大多数指令都在一个单周期内执行。主要特点指令是条件执行的内存访问使用Load/store架构。 二、Thumb 指令集 
Thumb是一个16位的指令集是ARM指令集的功能子集它对C代码的密度做了优化大约是ARM代码大小的65%提高了窄内存的性能 对大多数的Thumb指令而言没有使用条件执行标志一直都是置位的源寄存器和目标寄存器是相同的只使用了低端寄存器常量有大小的限制没有使用内嵌桶形移位器。 通过BX指令来切换ARM态和Thumb态。 Thumb不是一个“常规”指令集一般由编译器生成手动编写代码。 
三、ARM和Thumb的性能对比 四、Thumb-2指令集 
Thumb-2指令集主要在保留了完整的16位Thumb指令集的基础上增加了32位指令实现了几乎所有的ARM指令集架构的功能。 ARM 1156T2-S和Cortex系列支持Thumb-2 Cortex-M3只支持Thumb-2 设计目标以Thumb的指令密度达到ARM的性能 编译器可以自动地选择16位和32位指令的混合不需要手动选择减少了剖析代码和理解执行方式的需求。 可以访问ARM态的行为包括异常处理、访问协处理器、高级数据处理等。 条件执行方面新增If-Then(IT)指令1-4条紧接指令可以条件性地执行。 
五、常用ARM指令 
指令分类 
数据处理指令: 数据处理指令可分为数据传送指令、算术逻辑运算指令和比较指令等。数据传送指令: 用于在寄存器和存储器之间进行数据的双向传输。算术逻辑运算指令: 完成常用的算术与逻辑的运算该类指令不但将运算结果保存在目的寄存器中同时更新CPSR中的相应条件标志位。 
5.1、MOV指令 
5.1.1、MOV 
语法MOV{条件}{S} 目的寄存器源操作数 功能 MOV指令完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值当没有S时指令不更新CPSR中条件标志位的值。 指令示例 MOV r0, #0x1 ;将立即数0x1传送到寄存器R0 MOV R1R0 ;将寄存器R0的值传送到寄存器R1 MOV PCR14 ;将寄存器R14的值传送到PC常用于子程序返回 MOV R1R0LSL 3 ;将寄存器R0的值左移3位后传送到R1 【注不区分大小写】 
以下赋值是错误的  
5.1.2、立即数 
立即数是由 0-255之间的数据循环右移偶数位生成。 判断规则如下 
把数据转换成二进制形式从低位到高位写成4位1组的形式最高位一组不够4位的在最高位前面补0。数1的个数如果大于8个肯定不是立即数如果小于等于8进行下面步骤。如果数据中间有连续的大于等于24个0,循环左移2的倍数使高位全为0。找到最高位的1去掉前面最大偶数个0。找到最低位的1去掉后面最大偶数个0。数剩下的位数如果小于等于8位那么这个数就是立即数反之就不是立即数。 而例子中的数是0xfff,我们来看下他的二进制: 0000 0000 0000 0000 0000 1111 1111 1111 按照上述规则我们最终操作结果如下 1111 1111 1111 可以看到剩余的位数大于8个所以该数不是立即数 MOV机器码 AREA Example,CODE,READONLY    ;声明代码段ExampleENTRY ;程序入口
Start 
//测试代码添加在以下位置即可后面不再贴完整代码                                 mov r1,#0x80000001   
OVEREND然后点击debug按钮查看对应的机器码  得到mov r1,#0x80000001指令的机器码是E3A01106  MOV机器指令格式 用ARM指令助记符表示为 
opcode {cond} {S} Rd, Rn, shift_op2每个域的含义如下 1). { }条件码域 指令允许执行的条件编码。花括号表示此项可缺省。 ARM指令的一个重要特点是可以条件执行每条ARM指令的条件码域包含4位条件码共16种。几乎所有指令均根据CPSR中条件码的状态和指令条件码域的设置有条件的执行。当指令执行条件满足时指令被执行否则被忽略。指令条件码及其助记符后缀表示参见下表。 每种条件码可用两个字符表示这两个字符可以作为后缀添加在指令助记符的后面和指令同时使用。 例如跳转指令B可以加上后缀EQ变为BEQ表示“相等则跳转”即当CPSR中的Z标志置位时发生跳转。 2) 操作码域 指令编码的助记符 3) {S} 条件码设置域 这是一个可选项当在指令中设置{S}域时指令执行的结果将会影响程序状态寄存器CPSR中相应的状态标志。例如 
ADD R0R1R2R1与R2的和存放到R0寄存器中不影响状态寄存器
ADDS R0R1R2 执行加法的同时影响状态寄存器指令中比较特殊的是CMP指令它不需要加S后缀就默认地根据计算结构更改程序状态寄存器。 4) 目的操作数 ARM指令中的目的操作数总是一个寄存器。如果与第一操作数寄存器相同也必须要指明不能缺省。 5) 第一操作数 ARM指令中的第一操作数也必须是个寄存器。 6) shift_op2第二操作数 在第二操作数中可以是寄存器、内存存储单元或者立即数。 如果是立即数 bit:[11-8]表示操作数向左移动的位数/2, bit:[7-0]表示最终的操作数 
根据MOV指令格式我们分析各个位域的值  立即数0x80000001二进制为1000 0000 0000 0000 0000 0000 0000 0001 循环左移2位后得到以下结果00 0000 0000 0000 0000 0000 0000 0001 10 所以shifter的值为2/21操作数的值为0000 0110。 
5.2、移位操作 
ARM微处理器支持数据的移位操作移位操作在ARM指令集中不作为单独的指令使用它只能作为指令格式中是一个字段在汇编语言中表示为指令中的选项。移位操作包括如下6种类型ASL和LSL是等价的可以自由互换 
1) LSL或ASL逻辑算术左移 
寻址格式通用寄存器LSL或ASL 操作数 完成对通用寄存器中的内容进行逻辑或算术的左移操作按操作数所指定的数量向左移位低位用零来填充。其中操作数可以是通用寄存器也可以是立即数031。如: MOV R0, R1, LSL#2 将R1中的内容左移两位后传送到R0中 
2) LSR逻辑右移 
寻址格式通用寄存器LSR 操作数 完成对通用寄存器中的内容进行右移的操作按操作数所指定的数量向右移位左端用零来填充。其中操作数可以是通用寄存器也可以是立即数031。如 
MOV    R0, R1, LSR #2  将R1中的内容右移两位后传送到R0中左端用零来填充。3) ASR算术右移 
通用寄存器ASR 操作数 完成对通用寄存器中的内容进行右移的操作按操作数所指定的数量向右移位左端用第31位的值来填充。其中操作数可以是通用寄存器也可以是立即数031。如 
MOV    R0, R1, ASR #2  将R1中的内容右移两位后传送到R0中左端用第31位的值来填充。4) ROR循环右移 
通用寄存器ROR 操作数 完成对通用寄存器中的内容进行循环右移的操作按操作数所指定的数量向右循环移位左端用右端移出的位来填充。其中操作数可以是通用寄存器也可以是立即数031。显然当进行32位的循环右移操作时通用寄存器中的值不改变。如 
MOV    R0, R1, ROR #2  将R1中的内容循环右移两位后传送到R0中。RRX带扩展的循环右移 寻址格式通用寄存器RRX 操作数 完成对通用寄存器中的内容进行带扩展的循环右移的操作按操作数所指定的数量向右循环移位左端用进位标志位C来填充。其中操作数可以是通用寄存器也可以是立即数031。如 
MOV    R0, R1, RRX #2  将R1中的内容进行带扩展的循环右移两位后传送到R0中。; 第二操作数 寄存器移位操作 5种移位方式 9种语法 ;逻辑左移mov r0, #0x1mov r1, r0, lsl #1    ; 移位位数1-31肯定合法mov r0, #0x2mov r1, r0, lsr #1    ; 逻辑右移mov r0, #0xffffffffmov r1, r0, asr #1    ; 算术右移符号位不变 次高位补符号位mov r0, #0x7fffffffmov r1, r0, asr #1mov r0, #0x7fffffffmov r1, r0, ror #1 ; 循环右移mov r0, #0xffffffffmov r1, r0, rrx ; 唯一不需要指定循环位数的移位方式;带扩展的循环右移;C标志位进入最高位最低位进入C 标志位; 移位值可以是另一个寄存器的值低5bit 写法如下 mov r2, #1mov r0, #0x1mov r1, r0, lsl r2    ; 移位位数1-31肯定合法mov r0, #0xffffffffmov r1, r0, asr r2    ; 算术右移符号位不变 次高位补符号位mov r0, #0x7fffffffmov r1, r0, asr r2mov r0, #0x7fffffffmov r1, r0, ror r2 ; 循环右移5.3、CMP比较指令 
CMP{条件} 操作数1操作数2CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较同时更新CPSR中条件标志位的值。该指令进行一次减法运算但不存储结果只更改条件标志位。cmp是做一次减法并不保存结果仅仅用来产生一个逻辑体现在改变cpsr相应的condition位。 标志位表示的是操作数1与操作数2的关系(大、小、相等) 指令示例 
CMP R1R0   将寄存器R1的值与寄存器R0的值相减并根据结果设置CPSR的标志位
CMP R1#100 将寄存器R1的值与立即数100相减并根据结果设置CPSR的标志位5.4、TST条件指令 
TST{条件}  操作数1操作数2TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数据而操作数2是一个位掩码根据测试结果设置相应标志位。当位与结果为0时EQ位被设置。 指令示例 
TST   R11  用于测试在寄存器R1中是否设置了最低位表示二进制数。比较指令和条件执行举例 例1找出三个寄存器中数据最大的数 
mov r0, #3mov r1, #4mov r2, #5cmp r1,r0movgt r0,r1cmp r2,r0movgt r0,r2例2求两个数的差的绝对值 mov r0,#9mov r1,#15cmp r0,r1beq stopsubgt r0,r0,r1sublt r1,r1,r05.5、数据的处理指令 
ADD 
ADD{条件}{S} 目的寄存器操作数1操作数2ADD指令用于把两个操作数相加并将结果存放到目的寄存器中。操作数1应是一个寄存器操作数2可以是一个寄存器被移位的寄存器或一个立即数。指令示例 
ADD  R0R1R2           R0  R1  R2
ADD  R0R1#256            R0  R1  256
ADD  R0R2R3LSL#1      R0  R2  (R3  1)ADC 除了正常做加法运算之外还要加上CPSR中的C条件标志位如果要影响CPSR中对应位加后缀S。 
SUB SUB指令的格式为 SUB{条件}{S} 目的寄存器操作数1操作数2SUB指令用于把操作数1减去操作数2并将结果存放到目的寄存器中。操作数1应是一个寄存器操作数2可以是一个寄存器被移位的寄存器或一个立即数。该指令可用于有符号数或无符号数的减法运算。 如 
SUB  R0R1R2          R0  R1 - R2
SUB  R0R1#256        R0  R1 - 256
SUB  R0R2R3LSL#1   R0  R2 - (R3  1)SBC 除了正常做加法运算之外还要再减去CPSR中C条件标志位的反码 根据执行结果设置CPSR对应的标志位 AND指令的格式为 
AND{条件}{S} 目的寄存器操作数1操作数2AND指令用于在两个操作数上进行逻辑与运算并把结果放置到目的寄存器中。操作数1应是一个寄存器操作数2可以是一个寄存器被移位的寄存器或一个立即数。该指令常用于屏蔽操作数1的某些位。如 
AND  R0R03            该指令保持R0的0、1位其余位清零。ORR ORR指令的格式为 
ORR{条件}{S} 目的寄存器操作数1操作数2ORR指令用于在两个操作数上进行逻辑或运算并把结果放置到目的寄存器中。操作数1应是一个寄存器操作数2可以是一个寄存器被移位的寄存器或一个立即数。该指令常用于设置操作数1的某些位。如 
ORR  R0R03            该指令设置R0的0、1位其余位保持不变。BIC 这是一个非常实用的指令在实际寄存器操作经常要将某些位清零但是又不想影响其他位的值就可以使用该命令。 BIC指令的格式为 
BIC{条件}{S} 目的寄存器操作数1操作数2BIC指令用于清除操作数1的某些位并把结果放置到目的寄存器中。 操作数1应是一个寄存器操作数2可以是一个寄存器被移位的寄存器或一个立即数。操作数2为32位的掩码如果在掩码中设置了某一位则清除这一位。未设置的掩码位保持不变。 如 
BIC  R0R01011     该指令清除 R0 中的位 0、1、和 3其余的位保持不变。数据处理指令举例 1. 加法运算 mov r0, #1mov r1, #2add r2, r0, r1 ; r2  r0  r1add r2, r0, #4add r2, r0, r1, lsl #2 ;  r2  r0 R1 R0  R1*42. adc64位加法运算的实现 ; 2. adc  64位加法 r0, r1   r0, r1  r2, r3 mov r0, #0mov r1, #0xffffffffmov r2, #0mov r3, #0x1 adds r1, r1, r3 ; r1  r1  r3  必须加S后缀adc r0, r0, r2 ; r0  r0  r2  c ;add  带 扩展的加法可以对比下add和adds没有加s的话是不会影响条件位的。 
3. 减法 
; 3. sub  rd  rn - op2 
mov r0, #1
sub r0, r0, #1 ; r0  r0 - 14. 64位减法 
; 4. sbc  64位减法 r0, r1   r0, r1 - r2, r3 ; cpsr c 对于加法运算 C  1 则代表有进位 C  0 无进位;   对于减法运算 C  1 则代表无借位 C  0 有借位mov r0, #0mov r1, #0x0mov r2, #0mov r3, #0x1subs r1, r1, r3 sbc r0, r0, r2   ;sbc  带扩展的减法   5. 位清除 ; 5. bic   位清除 mov r0, #0xffffffffbic r0, r0, #0xff       ; and r0, r0, #0xffffff00 执行结果 5.6、跳转指令 
跳转指令用于实现程序流程的跳转在ARM程序中有两种方法可以实现程序流程的跳转 
使用专门的跳转指令;直接向程序计数器PC写入跳转地址值通过向程序计数器PC写入跳转地址值可以实现在4GB的地址空间中的任意跳转在跳转之前结合使用。 使用以下指令可以保存将来的返回地址值从而实现在4GB连续的线性地址空间的子程序调用。 MOV LR,PC ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转包括以下4条指令 B 跳转指令 BL 带返回的跳转指令 BLX 带返回和状态切换的跳转指令thumb指令 BX 带状态切换的跳转指令thumb指令 
1、 B 指令 指令的格式为 B{条件}  目标地址B指令是最简单的跳转指令。一旦遇到一个 B 指令ARM 处理器将立即跳转到给定的目标地址从那里继续执行。 B label     程序无条件跳转到标号label处执行CMP R1 #0BEQ label      当CPSR寄存器中的Z条件码置位时程序跳转到标号Label处执行。2. BL 指令 BL 指令的格式为 
BL{条件}  目标地址BL是另一个跳转指令但跳转之前会在寄存器R14中保存PC当前值因此可以通过将R14 的内容重新加载到PC中来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。 BL label 当程序无条件跳转到标号Label处执行时同时将当前的PC值保存到R14中 子函数要返回执行以下指令即可 MOV PC,LR3. BL指令机器码 语法 
Branch :  B{cond} label
Branch with Link : BL{cond} subroutine_labelBL机器码格式如下  各域含义:  其中offset是24个bite最高位包含一个符号位1个单位表示偏移一条指令所以可以寻址±223条指令即±8M条指令。 而一条指令是4个字节所以最大寻址空间为±32MB的地址空间。 我们来看下以下代码 AREA Example,CODE,READONLY  ENTRY ;程序入口
Start            MOV R0,#0     MOV R1,#10BL ADD_SUM   B OVER        
ADD_SUMADD R0,R0,R1 MOV PC,LR    
OVEREND由上图所示 
第6行代码BL ADD_SUM 会跳转到第8行即第9行的代码第6行的指令的机器码是EB000000 根据BL的机器码我们可以得到offset的值是0x000000,也就是说该指令跳转本身而根据我们的分析第6行代码应该是向前跳转2条指令按道理offset是应该是2为什么是0呢 因为是3级流水线所以pc存储指令地址与正在处理指令地址之间相差8个字节pc的地址是预取指令地址而不是正在执行的指令的地址。 
4. 如何访问全部32-bit地址空间 可以手动设置LR寄存器然后装载到PC中。 
MOV lr, pc
LDR pc, dest在编译项目过程中ARM连接器linker会自动为长跳转超过32Mb范围。 ldr下一章会详细详细讲解。 举例 子函数多重嵌套调用如何从子函数返回 area first, code, readonlycode32entry
main; bl 指令, 子函数调用mov r0,#1bl child_func  mov r0,#2
stop b stop 
child_funcmov r1,r0mov r2,lrmov r0, #3 //  pcbl child_func_2mov r0,#4mov r0,r1mov lr,r2mov pc, lr
child_func_2 ;叶子函数mov r3,r0mov r4,lr  ; 保存直接父函数用到的所有寄存器mov r0, #5mov r0,r3mov lr,r4 ;返回到直接父函数之前把它用到的所有寄存器内容恢复mov pc, lrend由上述例子所示每调用一级子函数我们都把返回地址存入到未分组寄存器中但是未分组寄存器毕竟是有限的像Linux内核函数的调用层次往往很深通用寄存器根本不够用要想保存返回地址就需要对数据进行压栈那我们就要为每个模式的栈设置空间