4.ARM指令集

ARM指令集

  • 一、ARM指令格式

    < opcode > {< cond >} {S} < Rd >,< Rn >,< shift_operand >

    <>号内是必须的,{}号内的项是可选的

    • opcode(operation code):指令助记符(操作码),例如,加法(ADD)、减法(SUB)、乘法(MUL)、除法(DIV)等

    • cond(condition)

      • 条件:根据条件是否执行指令(条件码
      • 原理:
        ARM系统中提供了一个专门的寄存器(当前程序状态寄存器)CPSR
        记录当前CPU的运行状态,他的最高的四位会有一个相应的记录
        条件码会去查询CPSR寄存器的最高四位是否满足条件
      • 常用条件:
        • 1、NE(Not Equal):不相等
        • 2、EQ(Equal):相等
        • 3、GT(Greater Than):大于
        • 4、LT(Less Then):小于
        • 5、GE(Greater Equal):大于或者等于
        • 6、LE(Less Equal):小于或者等于
        • 条件码
    • S

      • 表示指令执行的结果,决定是否影响CPSR寄存器的N/Z/C/V值
      • N:Negative(上一条指令结果是否为负数)
      • Z:Zero(上一条指令结果是否为0)
      • C:Carry(无符号算数运算是否进位的情况)
      • V:Overflow(有符号算数运算是否溢出的情况)
      • 包含S则影响,否则不影响
    • Rd(Destination Register)

      • 目标寄存器,主要用于存放计算的结果需要放到哪里去
      • 存放指令执行的结果R0~R15
    • Rn

      • 第1个操作数,必须是—个寄存器,可省略
    • shift_operand

      • 第2个操作数
        • 立即数
          • 一个常数,该常数必须对应8位位图,即—个8位的常数通过循环右移偶数位得到该数,该数为合法立即数
          • mov r1,#100
        • 寄存器 mov r2,r1
        • 寄存器移位(移位指令)
          • 将寄存器值读取之后,进行移位运算后,作为操作数2
          • LSL(Logic Shifter Left):逻辑左移(低位补0)
          • LSR(Logic Shifter Right):逻辑右移(高位补0)
          • 有符号数据左移用逻辑左移代替
          • ASR(Arithmetic Shifter Right):算术右移(正数:低位丢弃,高位补0 负数:低位丢弃,高位补1)
          • 举例:
            • r0,lsr #4表示r0 >> 4
            • r0,lsr r1表示r0 >> r1
            • #3,lsl #4错误,只能是寄存器移位,不能是立即数
  • 二、合法立即数

    • 在ARM 指令中可以使用的立即数必须合法,否则导致ARM指令执行异常

      • 原因
        • ARM 指令长度有限 ,不能都用于表示立即数,所以不能表示所有的立即数,最终会导致部分立即数不能表示
    • 合法立即数规则

      • 如果立即数记做 immediate ,8位常数记做immed_8,4位的循环右移值记做 rotate_imm
        immediate = immed_8循环右移(2*rotate_imm)
      • 所有的立即数必须要通过一个8位立即数通过循环右移偶数位获得,否则为不合法
      • 0x3F0可以通过 0x3F循环右移28位得到,immed_8=0x3F,rotate_imm=0xE
      • 0x0480 0000 可以通过 0x12循环右移10位得到,immed_8=0x12,rotate_imm=0x5
      • 立即数
    • 合法立即数判断

      • 将对应的数转换为32位16进制数 例如:218=0xDA= 0x0000 00DA
      • 1、除零外,仅有一位数 例如:0x0001 0000、0x00f0 0000等
      • 2、除零外,仅有二位数,并且相邻(包括首尾相邻)
      • 3、除零外,仅有三位数,并且相邻(包括首尾相邻)
      • 4、0~255一定是立即数
      • 5、有效数:原数是立即数或者原数反码是立即数(0xFFFFFFFF)
  • 三、数据传送指令

    • MOV

      • 格式:MOV 目标寄存器,操作数2
      • 功能:将操作数2的值赋值给目标寄存器
      • mov r0,#1 @立即数1的值赋值给目标寄存器r0
        mov r1,r0 @寄存器r0的值赋值给目标寄存器r1
        
    • MVN

      • 格式:MVN 目标寄存器,操作数2
      • 功能:对内存中存储的值进行按位取反(~),将操作数2取反的值给目标寄存器
      • mov r0,#1 @立即数1的值赋值给目标寄存器r0
        mvn r1,#0 @立即数0按位取反的值赋值给目标寄存器r1
        
    • LDR(LoaD Register)

      • 格式:LDR 目标寄存器,= 数据(=表示把原始数据给目标寄存器)
      • 功能:将任意数据加载到目标寄存器中
      • ldr r0,=0x1234 @将十六进制数1234加载到目标寄存器r0
        
      • 为什么不用MOV存放到寄存器中?
        • MOV能存放的只有合法立即数
        • LDR可以直接将任意数据加载到寄存器中
  • 四、数据计算指令

    • ADD

      • 格式:ADD 目标寄存器,操作数1,操作数2
      • 功能:加法指令,将操作数1加上操作数2的结果存放在目标寄存器
      • ADD R0,R1,#2  ==>  R0 = R1 + 2
        ADD R0,R1,R2  ==>  R0 = R1 + R2
        ADD R0,R1,R2,LSL #3  ==>  R0 = R1 + R2 << 3
        
    • SUB

      • 格式:SUB 目标寄存器,操作数1,操作数2
      • 功能:减法指令,将操作数1减去操作数2的结果存放在目标寄存器
      • SUB R0,R1,#2  ==>  R0 = R1 - 2
        SUB R0,R1,R2  ==>  R0 = R1 - R2
        SUB R0,R1,R2,LSL #3  ==>  R0 = R1 - R2 << 3
        
    • MUL

      • 格式:MUL 目标寄存器,操作数1,操作数2
      • 功能:乘法指令,将操作数1乘以操作数2的结果存放在目标寄存器
      • 注意:操作数1和操作数2必须都是寄存器,并且操作数1的寄存器编号不能和目标寄存器一样
      • MUL r0,r1,r2
        MUL r0,r1,#3错误,操作数2为立即数
        MUL r0,r0,r1错误,操作数1的寄存器编号和目标寄存器一样
        MUL r0,r1,r0目标寄存器和操作数1 不一样 正确
        
  • 五、比较指令

    • CMP

      • 格式:CMP 寄存器,操作数2
      • CMP会影响CPSR, 也会影响带条件执行的指令的结果
      • 条件码:NE(!=)、EQ(= =)、LT(<)、GT(>)、GE(>=)、LE(<=)
      • mov r0,#10      ==>a = 10;
        mov r1,#20      ==>b = 20;
        mov r2,#30      ==>c = 30;
        cmp r0,r1       ==>if (a > b)
        addgt r1,r1,#1  ==>b++;
        cmp r0,r2       ==>if (a <= c)
        addle r2,r2,#1  ==>c++;
        
  • 六、跳转指令

    • B

      • 格式:B{条件} 标签名
      • 功能:跳转到指定目标地址
      • @1 + 2 + ... + 100
        	mov r0,#0 @sum = 0;
        	mov r1,#1 @i = 1;
        loop:
        	add r0,r0,r1 @sum = sum + i;
        	add r1,r1,#1 @i = i + 1
        	cmp r1,#100 
        	ble loop @if (r1 <= 100) goto loop
        
    • BL

      • 格式:BL{条件} 标签名
      • 功能:跳到一个指定的标签,BL跳转之前,会将跳转前的PC的值保存到 LR 寄存器中
      • 	mov r0,#1
        	bl out @跳转到out
        	mov r0,#3
        out:
        	mov r0,#2
        	mov pc,lr @回到bl指令的下一条指令地址继续执行
        
    • B指令+标签可实现BL指令类似功能

      B/BL跳转指令的范围:+/-32M

    • 给PC赋值

      • 格式:LDR PC,=标签名
      • 功能:将PC指针指向标签表示的地址
      • mov pc,lr @回到bl指令的下一条指令地址继续执行
        
  • 七、位运算

    • AND

      • 格式:AND 目标寄存器,操作数1,操作数2
      • 功能:按位与,将操作数1与操作数2按位与的结果存放在目标寄存器
      • AND R0,R1,#2 ==>R0 = R1 AND 2
        AND R0,R1,R2 ==>R0 = R1 AND R2
        AND R0,R1,R2,LSL #3 ==>R0 = R1 AND (R2 << 3)
            
        @AND按位与运算:0x12345678,将它的高16位存放在r0中,它的低16位存放在r1中,然后将它的高16位和低16位相加
        ldr r2,=0x12345678
        ldr r0,=0x0000FFFF
        AND r1,r2,r0
        mov r0,r2,lsr #16
        add r0,r0,r1
        
    • ORR

      • 格式:ORR 目标寄存器,操作数1,操作数2
      • 功能:按位或,将操作数1与操作数2按位或的结果存放在目标寄存器
      • ORR R0,R1,#2 ==>R0 = R1 ORR 2
        ORR R0,R1,R2 ==>R0 = R1 ORR R2
        ORR R0,R1,R2,LSL #3 ==>R0 = R1 ORR (R2 << 3)
            
        @ORR按位或运算:5 ORR 1 = 5
        mov r0,#5 @0101
        mov r1,#1 @0001
        orr r1,r0,r1 @0101--5
        
    • EOR

      • 格式:EOR 目标寄存器,操作数1,操作数2
      • 功能:按位异或,将操作数1与操作数2按位异或的结果存放在目标寄存器
      • EOR R0,R1,#2 ==>R0 = R1 EOR 2
        EOR R0,R1,R2 ==>R0 = R1 EOR R2
        EOR R0,R1,R2,LSL #3 ==>R0 = R1 EOR (R2 << 3)
            
        @EOR按位异或运算:1 EOR 5 = 4
        mov r0,#1 @0001
        mov r1,#5 @0101
        eor r0,r0,r1 @0100--4
        
    • BIC(BIC<==>&~)

      • 格式:BIC 目标寄存器,操作数1,操作数2
      • 功能:位清除
        操作数1按位与操作数2取反的结果存放在目标寄存器(操作数1 &~ 操作数2
      • @BIC位清除运算:7 BIC 3 = 4
        mov r0,#7 @0111
        mov r1,#3 @0011		
        bic r0,r0,r1 @0100--4==>操作数1二进制的位与操作数2二进制相对应为1的位直接置0就是最终结果
            
        BIC r1,r0,#0xa
        0xa				0000 1010
        ~0xa			1111 0101
        0xff    		1111 1111
        0xff & ~0xa		1111 0101
        
      • 将某一位置1,与1进行或操作,结果一定是1,与0进行或操作 结果保持不变 ,1 | 1 = 1,0 | 1 = 1,0 | 0 = 0 ,1 |0 = 1
      • 将某一位清0,与0进行与操作,结果一定是0,与1进行&操作,结果保持不变,1 & 1 = 1,0 & 1 = 0,0 & 0 = 0 ,1 &0 = 0
      •   0xabcd将它的[3:1]设置为101,然后将它的[11:7]0
              
          15	14	13	12	11	10	9	8	7	6	5	4	3	2	1	0
          1	0	1	0   [1	0	1	1	1]	1	0	0  [1	1	0]	1
              
          data = 0xabcd
          data = data & ~(7 << 1) //[3:1]清0
          data = data | (0x5 << 1)//[3:1]设置为101
          data = data & ~(0x1f << 7)//[11:7]清0
              
          有一个数据32bit的data,将它的[18:9]0,将它的[10:4]变成1010011,其他位不变
          data = data & ~(0x3ff << 9)//[18:9]清0
          data = data & ~(0x7f << 4)//[10:4]清0
          data = data | (0x53 << 4)//[10:4]设置为1010011
        
  • 八、内存访问指令

    • 单寄存器操作

      • LDR(Load Register)加载
        • 格式:
          • 1、LDR 目标寄存器,= 数据
          • 2、LDR Rd, [Rn, #offset]
            Rd是目标寄存器,用于存储加载的值
            Rn是基址寄存器,用于指定内存地址的基址
            #offset是一个立即数偏移量,用于指定相对于基址的偏移地址
        • 功能:将内存中的值加载到寄存器中、读内存、C语言中专门存储地址的变量(指针变量)
        • LDR R0,[R1, #4]; 将R1寄存器中存储的地址+4的位置的值加载到R0寄存器中
      • STR(Store Register)存储
        • 格式:STR Rd, [Rn, #offset]
          Rd是源寄存器,存储需要存储的值
          Rn是基址寄存器,用于指定内存地址的基址
          #offset是一个立即数偏移量,用于指定相对于基址的偏移地址
        • 功能:将寄存器中的值存储到内存中、写内存
        • STR R2,[R3, #8]; 将R2寄存器中的值存储到R3寄存器中存储的地址+8的位置
      • 地址寻址模式
        • 寄存器间接寻址模式
          • 格式:
            • 1、LDR R0,[R1] 将R1寄存器中的值作为地址,取出里面的值读到R0中(R0 = *R1
            • 2、STR R0,[R1] 将R0寄存器中的值写到R1存放的地址中(*R2 = R0
          • 功能:
            • 通过寄存器获得要访问的内存地址,再进行操作,一般只涉及一个数据的操作
              中括号[] 内的寄存器表示该寄存器当中存了一个地址
          • @内存访问指令
            @ldr r0,=0x12345678
            @mov r1,#0x40000000 @ int *p = (int *)0x40000000
            @str r0,[r1] @ *r1 = r0 将r0的值存到0x40000000 *p = 0x12345678
            @ldr r2,[r1] @ r2 = *r1 将0x40000000的值存储到r2中 r2 = *p
            	
            @将0x1234写到0x4000,0000 ,0xabcd写到0x4000,0004,然后从这两个地址读取数据做累加,最终结果存放在r0
            ldr r0,=0x1234
            mov r1,#0x40000000
            str r0,[r1] @将0x1234写到0x4000,0000
            ldr r0,=0xabcd
            mov r2,#0x40000004
            str r0,[r2] @将0xabcd写到0x4000,0004
            ldr r0,[r1]
            ldr r3,[r2]
            add r0,r0,r3 @累加(0x1234 + 0xabcd = 0xBE01
        • 基址寻址模式
          • 设定一个基础地址,后续寻址则基于这个基础地址进行偏移,将基地址寄存器加上指令中给出的偏移量,得到数据存放的地址
          • 前索引
            • 功能:先偏移,再取值
            • 格式:
              • 1、==STR r0,[r1,#4] > *(r1 + 4) = r0
              • 2、==LDR r0,[r1,#4] > r0 = *(r1 + 4)
            • @基址寻址模式(前索引)先偏移,后赋值
              ldr r0,=0x1234
              mov r1,#0x40000000
              str r0,[r1,#4] @从基地址开始偏移4(r0 = *(r1 + 4))
              ldr r2,[r1,#4]
              
          • 后索引
            • 功能:先取值,再偏移(自动更新基地址)
            • 格式:
              • 1、==STR r0,[r1],#4 > *r1 = r0,r1 = r1 + 4
              • 2、==LDR r0,[r1],#4 > r0 = *r1,r1 = r1 + 4
            • @基址寻址模式(后索引)先赋值,后偏移(自动更新基地址)
              ldr r0,=0x1234
              mov r1,#0x40000000
              str r0,[r1],#4 @ r0 = *r1,r1 = r1 + 4
              @ldr r2,[r1] @错误,r1中没有数据
              mov r2,#0x40000000
              ldr r3,[r2]
              
          • 自动索引
            • 功能:先偏移,再取值,并更新基地址
            • 格式:
              • 1、==STR r0,[r1,#4]! > *(r1 + 4) = r0,r1 = r1 + 4
              • 2、==LDR r0,[r1,#4]! > r0 = *(r1 + 4),r1 = r1 + 4
            • @基址寻址模式(自动索引)先偏移,后赋值,更新基地址
              ldr r0,=0x1234
              mov r1,#0x40000000
              str r0,[r1,#4]! @r0 = *(r1 + 4),r1 = r1 + 4
              ldr r2,[r1]
              
        • 两种模式都需要将内存地址保存到寄存器中,需要使用 LDR 伪指令用法ldr r0,=0x40000000
        • @将1-10数据存放在基地址为Ox4000,0000,0x4000,0000起始地址的值拷贝到0x4000,0100
          	mov r0,#0x40000000 @基地址
          	mov r1,#1 @i = 1
          	mov r2,#10 @num = 10
          	bl store_data @跳转到store_data,将PC值保存到LR
          	
          	mov r0,#0x40000000 @存储基地址
          	ldr r1,=0x40000100 @拷贝基地址
          	bl copy_data @跳转到copy_data,将PC值保存到LR
          	
          store_data:
          	str r1,[r0],#4 @*r0 = r1,r0 = r0 + 4
          	add r1,r1,#1 @r1 = r1 + 1
          	cmp r1,r2
          	ble store_data @if (r1 <= r2) goto store_data
          	
          	mov pc,lr @回到bl store_data下一条语句
          	
          copy_data:
          	ldr r3,[r0],#4
          	str r3,[r1],#4 @*r1 = r3,r1 = r1 + 4
          	sub r2,r2,#1 @i = i - 1
          	cmp r2,#0
          	bgt copy_data @if (r2 > 0) goto copy_data
          
      • 将内存地址保存到寄存器中
        • ldr 目标寄存器,=label
      • keil 内存数据仿真
        • 魔法棒(Options for target…)=>Linker=>Data Start:设置数据段起始地址(0x40000000
        • Keil4仿真起始地址
    • 多寄存器操作

      • LDM
        • 格式:LDM{条件}{s}< MODE > 基址寄存器{!},{Reglist}^
        • 功能:将一块内存数据,加载到多个寄存器中
      • STM
        • 格式:STM{条件}{s}< MODE > 基址寄存器{!},{Reglist}^
          • 基址寄存器:用来存放内存的起始地址
          • !:最后更新基址寄存器的值
          • Reglist:多个寄存器,从小到大, 不连续{r0,r2,r3}或连续{r0-r7}
            寄存器号大的对应内存的高地址,寄存器号小的对应内存的低地址
          • ^:
            • 若 ^存在,如果Reglist没有PC的时候,这个时候操作的寄存器是用户模式下的寄存器
            • 在LDM指令中,有PC的时候,在数据传送的时候,会将SPSR的值拷贝到CPSR,用于异常的返回
        • 功能:将多个寄存器的值,存储到一段内存中
      • MODE(地址模式)
        • IA(Increment After)先操作寄存器(值),后增加地址
          • mov r0,#0x10
            mov r1,#0x20
            mov r2,#0x30
            ldr r3,=0x40000100
            @IA:先操作寄存器(值),后增加地址
            stmia r3,{r0-r2} @寄存器列表,将 r0-r2 的值依次存放到r3对应的内存地址空间(低地址--->高地址)
            ldmia r3,{r4-r6} @将r3内存地址对应的连续三个值依次加载到r4,r5,r6
            
        • IB(Increment Before)先增加地址,后操作寄存器(值)
          • mov r0,#0x10
            mov r1,#0x20
            mov r2,#0x30
            ldr r3,=0x40000100
            @IB:先增加地址,后操作寄存器(值)
            stmib r3,{r0-r2} @寄存器列表,将 r0-r2 的值依次存放到r3对应的内存地址空间(低地址--->高地址)
            ldmib r3,{r4-r6} @将r3内存地址对应的连续三个值依次加载到r4,r5,r6
            
        • DA(Decrement After)先操作寄存器,后减少地址
          • mov r0,#0x10
            mov r1,#0x20
            mov r2,#0x30
            ldr r7,=0x4000010C
            @DA:先操作寄存器(值),后减小地址
            stmda r7,{r0-r2} @寄存器列表,将 r0-r2 的值依次存放到r7对应的内存地址空间(低地址--->高地址)
            ldmda r7,{r4-r6} @将r7内存地址对应的连续三个值依次加载到r4,r5,r6
            
        • DB(Decrement Before)先减少地址,后操作寄存器
          • mov r0,#0x10
            mov r1,#0x20
            mov r2,#0x30
            ldr r7,=0x4000010C
            @DB:先减小地址,后操作寄存器(值)
            stmdb r7,{r0-r2} @寄存器列表,将 r0-r2 的值依次存放到r7对应的内存地址空间(低地址--->高地址)
            ldmdb r7,{r4-r6} @将r7内存地址对应的连续三个值依次加载到r4,r5,r6
            
        • 在操作地址时,必须遵循大地址对应大寄存器编号,小地址对应小寄存器编号
        • 地址操作模式
      • @在0x40000000地址依次将r1=10,r2=20,r3=30,r5=50存入,然后r1到r5清零,在从内存读到r1到r5,得到原始数值
        mov r0,#0x40000000
        mov r1,#10
        mov r2,#20
        mov r3,#30
        mov r5,#50
        stmia r0!,{r1-r3,r5} @寄存器数据写入内存,更新基址寄存器的地址
        @清空寄存器值
        mov r1,#0
        mov r2,#0
        mov r3,#0
        mov r5,#0
        
        @读出内存数据到寄存器
        ldmdb r0!,{r1-r3,r5}
        
  • 九、SPSR/CPSR操作指令

    • 读操作

      • 格式:MRS Rn, CPSR/SPSR
        MRS:Move to Register from State register
        MRS R0,CPSR; @传送CPSR的内容到R0
        MRS R0,SPSR; @传送SPSR的内容到R0
        
      • 功能:将状态寄存器的值,读到通用寄存器
      • 使用场景:
        • 需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
        • 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
    • 写操作

      • 格式:MSR CPSR/SPSR, Rn
        MSR:Move to State register from Register
        MSR CPSR,R0; @传送R0的内容到CPSR
        MSR SPSR,R0; @传送R0的内容到SPSR
        MSR CPSR_c,R0; @传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域(低8位)
        
      • 功能:将通用寄存器的值,写到状态寄存器
    • @将CPSR的第7(I)0,其他位不变(效果:使能IRQ(一般中断模式)异常)
          mrs r0,cpsr @将cpsr的值读到一个通用寄存器
          mov r1,#1 @先将1写入r1
      	bic r0,r0,r1,lsl #7 @再将r1逻辑左移7位赋值给r0
          msr cpsr,r0 @再将r0写入cpsr
          
      @将CPSR的第7(I)1,其他位不变(效果:禁用IRQ异常)
      	mrs r0,cpsr @将cpsr的值读到一个通用寄存器
          mov r1,#1 @先将1写入r1
      	orr r0,r0,r1,lsl #7 @再将r1逻辑左移7位赋值给r0
          msr cpsr,r0 @再将r0写入cpsr
      

      CPSR第I位默认为1

      不能对CPSR直接使用BIC运算,需要借助其他寄存器

    • CPSR

  • 十、栈操作指令(操作R13)

    • 出栈

      • 格式:LDM sp!,{registers(寄存器列表)}
    • 进栈

      • 格式:STM sp!,{registers(寄存器列表)}
    • 在对栈操作之前,必须先设置sp(Stack Pointer)的值

    • 空栈与满栈

      • 堆栈指针(sp)指向最后压入堆栈的有效数据项,称为满堆栈;
        堆栈指针(sp)指向下一个待压入数据的空位置,称为空堆栈。
    • 栈操作四种模式(不是数据结构中的栈)

      • 满栈递增(FA)
        • Full Ascending
        • 入栈是向高地址的方式移动,然后再存入数据;出栈是先拿出数据,然后向低地址方向移动
      • 满栈递减(FD)
        • 默认满递减(Full Desending)
        • 入栈是向低地址的方式移动,然后再存入数据;出栈是先拿出数据,然后向高地址方向移动
      • 满栈
      • 空栈递增(EA)
        • Empty Ascending
        • 入栈先存入数据,然后向高地址方向递增;出栈是先向低地址方向移动,然后再拿出数据
      • 空栈递减(ED)
        • Empty Desending
        • 入栈先存入数据,然后向低地址方向递增;出栈是先向高地址方向移动,然后再拿出数据
      • 空栈
    • sp设为0x40000000可以吗?

      • 栈模式默认满栈递减,不能设置为0x40000000为开始地址
        应当设置0x40001fff为起始地址
        但由于0x40001fff 末尾f是15这不是一个4字节对齐的地址,所以应当设置为0x40001ff0
    • @将r1 #10, r2 #20进栈和出栈
          ldr sp,=0x40001ff0
          mov r1,#10
      	mov r2,#20
      	stmfd sp!,{r1-r2}
      	mov r1,#0
      	mov r2,#0
      	ldmfd sp!,{r1-r2}
      
  • 十一、指令流水线

    • 增加处理器指令流的速度,提高效率,ARM7 系列使用3级流水线,允许多个操作同时处理,而非顺序执行。(取址、解码、执行)

    • ARM7系列三级流水线

      ARM:32位 Thumb:16位

    • 最佳流水线(F、D、E)

      • 所有的操作都在寄存器中(单周期执行)
        指令周期数 (CPI) = 1
    • LDR流水线(F、D、E、M、W、S)

      • 指令周期数 (CPI) = 1.5
      • S:访问内存,性能降低,要想提高效率,就要加人,出现多级流水线
    • 分支流水线(F、D、E、L、A)

      • 流水线被阻断。注意:内核运行在ARM状态
      • 发生跳转性能降低,预取和解码浪费了
        仿真情况和我们实际情况不一样,指令执行时,预取实际在底下的命令
        C++中inline关键字可以减少跳转
    • 中断流水线(F、D、E、DI、EI、L、A)

      • IRQ 中断的反应时间最小=7周期
    • F:Fetch D:Decode E:Execute M:Memory W:Writeback

      S:Stall(阻隔) DI:Decode IRQ EI:Execute IRQ L:Linkret

      A:Adjust

  • 十二、伪指令

    • 定义

      • 伪指令不是CPU真正的指令,是为了方便程序员使用编译器设计的指令
        这个指令ARM核无法直接识别,需要编译器对他翻译成ARM核所能识别的指令
        编译器在编译的过程中,把伪指令翻译成几条真正的指令实现
    • 伪指令举例

      • LDR 目标寄存器,=Label == > 将标签的地址直接赋值到目标寄存器中
        LDR 目标寄存器,Label == > 将标签对应地址的数据加载到目标寄存器中
        ADR 目标寄存器,Label == > 根据当前的PC的值+/-偏移量,动态获取当前Label所表示的内存地址
        .word 0x12345678 == > 在存储器分配4字节的内存单元,并将它初始化为0x12345678
    • LDR r0,[r1] == >ARM指令

    • 链接地址和运行地址

      • 链接地址:给编译器使用,它是告诉编译器第一条指令的地址,然后编译器根据这个地址推算出后面每条指令的地址
      • 运行地址:程序实际在内存中的运行地址
      • 理论上程序的链接地址就是最终程序的运行地址,如果最终程序运行地址和链接地址不一样,可能会导致程序无法正常执行标签的值会受到链接地址的影响
      • 链接地址
      • 链接地址与运行地址关系
        • 在操作系统中是虚拟地址,运行时进程会自动映射到它的地址,不需要关心;
          裸机上是物理地址,编译的时候是什么地址,运行也应该在什么地址。否则可能无法运行
      • 程序编译完成将会翻译成机器码,没有地址,不同的链接地址产生的机器码可能不一样,从而影响程序的执行
    • 如何判别代码在实际内存中运行的地址?

      • 正确方法:ADR r0,_start可以知道,因为它是根据PC的值,动态获取
        错误方法:LDR r0,= _start无法知道,这条指令不论在哪里运行,r0的值都是固定(取决于指定的链接地址)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值