zoukankan      html  css  js  c++  java
  • ARM(CPU)内部寄存器学习笔记


    本文的具体寄存器描述,以NXP LPC2000系列用到的内核ARM7TDMI-S processor为例,参考ARM官网

    提到ARM内部寄存器,就不得不提到ARM处理器状态和处理器模式,因为不同状态和模式下,访问寄存器的权限是完全不一样的。

    ARM处理器状态

    嵌入式系统对存储成本和空间要求比较高,为了让用户更好控制代码量,因此设计了2套指令系统:ARM指令集Thumb指令集
    ARM指令集:32bit字长,具有完整功能;
    Thumb指令集:16bit字长(半字长),能实现ARM指令集绝大部分内容。

    • 二者关系
    1. 功能上,Thumb指令集是ARM指令集的子集。
    2. Thumb指令集具有极高代码密度,平均缩减30%代码量。
    • 2种指令集何时执行?
      有2个处理器状态与这2套指令集对应,而这2种状态由CPSR寄存器的T字段控制:
    CPSR[T] = 0 <=> ARM状态
    CPSR[T] = 1 <=> Thumb状态
    
    1. ARM状态
      32bit,处理器执行ARM指令,处理器上电后默认状态。

    2. Thumb状态
      16bit,处理器执行半字方式的Thumb指令。

    参见下图对PSR寄存器(Program Status Register)描述,其中CPSR表示当前程序状态寄存器(Current Program Status Register):

    PS:

    1. 修改CPSR[T](或者说ARM状态和Thumb状态切换),并不影响处理器模式和其他寄存器内容;
    2. 不要使用MSR指令让处理器切换状态,虽然可以修改T位,但是因为不会清空流水线,所以是不安全的。推荐使用BX指令进行状态切换;
    • 状态切换
      BX指令控制处理器状态切换,程序发生跳转时,流水线会被清空:流水线中原来处理器状态取值和译码的指令,也会被清除,不会引起处理器错误。
    ; 从ARM状态 => Thumb状态
            CODE32                   ; 下面的指令为ARM指令
            LDR R0,=Lable+1          ; R0[bit0]=1, BX自动将CPSR[T]置1
            BX R0                    ; 切换到Thumb状态, 并跳转到Lable处执行
            CODE16                   ; 下面的指令为Thumb指令
    Lable MOVE R1,#12
    ; 从Thumb状态 => ARM状态
            CODE16                   ; 下面的指令为Thumb指令
            LDR R0,=Lable            ; R0[bit0]=0, BX自动将CPSR[T]置0
            BX R0                    ; 切换到ARM状态, 并跳转到Lable处执行
            CODE32                   ; 下面的指令为ARM指令
    Lable MOV R1,#10
    

    处理器模式

    ARM处理器支持7种处理器模式,以CPSR_M[4:0]控制位反应处理器正在操作的模式。除用户(user, usr)模式外,其他6种称为特权(privileged)模式,分为2类,分别是:系统(system,sys)模式和异常模式,
    其中,异常模式又包括5种模式: 管理(supervisor,svc)模式、中止(abort,abt)模式、未定义(undefined,und)模式、中断(interrupt request,irq)模式、快速中断(fast interrupt request,fiq)模式。

    ARM处理器7种模式:

    CPSR_M[4:0]表示当前处理器模式:

    注:

    1. nM[4:0]是M[4:0]的反转,nM[4:0]信号仅用于诊断和调试;
    2. 只有在特权模式下,才允许对CPSR进行读写。这也是为什么不能直接通过修改CPSR[T],以控制处理器状态切换,而是需要一个流程的原因。

    ## 异常模式 **异常模式** > 管理模式,中止模式,未定义模式,中断模式,快速中断模式 这5种处理器模式统称异常模式。

    每种异常都和一种处理器模式相对应,一旦应用程序发生特定异常中断时,处理器进入相应的异常模式,内核立即跳转到向量表中的某个入口地址,执行相应的处理程序。同时,每种异常模式都有与之对应的寄存器,供相应的异常处理程序用,用来确保处理器进入异常模式时,用户模式下的寄存器不会被破坏。

    • 什么时候进入异常模式?规定:
    1. 处理器复位后进入管理模式,操作系统内核通常处于该模式;
    2. 当处理器访问存储器失败时,进入数据访问中止模式;
    3. 当处理器遇到不支持的指令时,进入未定义模式;
    4. 中断模式与快速中断模式分别对ARM处理器两种不同级别的中断做出响应;
    • 系统模式切换到异常模式

    例,切换到管理模式(svc)

    MSR CPSR_c, #(NoInt | SVC32Mode) // 相当于 CPSR_c = (NoInt | SVC32Mode) => I = 1, F = 1, M[4:0] = 0b10011(Supervisor)
    

    MSR指令通常用于恢复或改变PSR内容;
    CPSR_c 表示CPSR的控制域掩码,而控制域指CSPR[7..0](control bits:I, F, T, M[4..0]);
    SVC32Mode 指的管理模式;

    CPSR_c,CPSR_f,CPSR_s,CPSR_x含义:

    Tips:MSR(写)和MRS(读)指令
    MRS指令:专门用于对状态寄存器CPSR和SPSR(Saved PSR)进行读操作。通过读取CSPR,可以获得当前处理器的工作状态。通过读取SPSR,可以获得处理器进入异常前的处理器状态(因为只有异常模式才有SPSR);
    MSR指令:专门用于对状态寄存器CPSR和SPSR进行写操作。跟MRS配合,可以实现对CPSR/SPSR的读写操作,以切换处理器模式、允许或禁止IRQ(IRQ disable)和FIQ(FIQ disable)中断等功能;

    关于MRS和MSR更详细内容,可参见这篇文章汇编指令-MRS(读)和MSR(写)指令操作CPSR寄存器和SPSR寄存器使用(1) | 博客园

    系统模式 System,Sys

    用户模式

    用户模式是程序正常运行的工作模式。

    系统模式与用户模式
    系统模式具有跟用户模式完全系统的寄存器,不过系统模式有特权,可以访问所有系统资源,也可以直接进行处理器模式切换。主要供OS的任务使用,当然也允许对CPSR读写。
    系统模式下,OS可以访问所有用户模式下相应的寄存器,而不是使用异常模式下相应的寄存器,这样可以保证当异常中断发生时,任务的状态不被破坏。

    系统模式与异常模式
    系统模式、用户模式都不能由异常进入。要进入系统模式,必须通过修改CPSR实现。

    例,从管理模式切换到系统模式

    MSR CPSR_c, #(NoInt | SYS32Mode) // 从管理模式切换到系统模式 => I = 1, F = 1, M[4:0] = 0b1111(Mode = System)
    

    ARM内部寄存器

    ARM处理器内部共有37个用户可访问32bit寄存器,分别是:

    • 31个通用寄存器
      R0~R15, R13_svc, R14_svc, R13_abt, R14_abt, R13_und, R14_und, R13_irq, R14_irq, R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq

    • 6个状态寄存器(每个只使用其中12bit)
      CPSR, SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq

    处理器有7种不同的处理器模式,每种模式都有一组相应的寄存器组,对应不同的后缀名,如R13_svc对应svc模式(管理模式)。
    PS:

    1. 每种模式拥有的一组寄存器不相同,并非上面描述的全部;
    2. 这些寄存器不能同时访问,何时访问取决于处理器状态和处理器模式。

    ARM状态和Thumb状态下的寄存器访问

    可以看到,ARM状态和Thumb状态下,程序员能访问的寄存器是不一样的。
    特别地,在ARM状态下,特殊用途寄存器R13(堆栈指针SP),R14(链接寄存器LR),R15(程序计数器PC),尽管可以当做通用寄存器使用,但是编译器通常认为R13始终指向一个有效的堆栈结构,所以一定要注意将R13当做通用寄存器来使用是非常危险的。

    ARM状态下,各种模式下能访问的通用寄存器和PC(程序计数器)

    Thumb状态下,各种模式下能访问的通用寄存器和PC(程序计数器)


    一般通用寄存器

    R0~R7 保存数据或地址值,任何处理器模式下通用,都是同一个32bit物理寄存器。

    PS:由用户模式进入中断模式后,可能造成寄存器的数据丢失,因此应该先对重要数据进行备份。

    R8~R14 所对应的物理寄存器取决于当前的处理器模式,几乎所有允许使用通用寄存器的指令都允许使用R8~R14。具体参见上面图“各种模式下能访问的通用寄存器和PC(程序计数器)”。

    不同模式下的寄存器

    CSPR的位域M[4:0]控制不同的处理器模式。下图展示了不同模式下、不同状态下各寄存器的可见性:


    堆栈指针R13(SP)

    堆栈的概念
    堆栈实际是指“堆”和“栈” 2个不同概念,但为了符合表达习惯,没有特别指出仅表示“栈”。
    堆栈是指

    在内存中划分出一段存储空间,这个存储空间就像是一个大的数据仓库,用于暂时保存一些数据。

    堆栈操作通常发生在子程序调用、异常发生、程序运行过程中寄存器数量不够时。

    • 程序调用、异常发生: 通常把子程序或异常服务程序将要用到的寄存器内容,保存到堆栈中,子程序或异常服务程序返回时再恢复,以确保原有程序不被破坏。
    • 程序运行过程中寄存器数量不够:如果程序运行过程中,局部变量太多,以至于处理器内部的寄存器无法全部装下,程序员或编译器会使用堆栈来作为数据的暂存空间,将暂未用到的数据压栈,需要用到时再出栈。

    链接寄存器R14(LR)

    ARM状态下,子程序返回地址将自动放入到R14中。每种异常模式都有专用的R14寄存器,用于保存子程序返回地址,分别是R14_svc,R14_abt,R14_und,R14_irq,R14_fiq。
    Thumb状态下,LR会自动链接到ARM状态R14。

    R14有2种特殊功能:

    1. 使用BL指令调用子程序时,返回地址将自动存入R14中。在子程序结束时,将R14复制到PC即可实现子程序的返回。。
    • 通常有2种方式实现子程序的返回:
    // 方式一
    MOV PC,LR
    // 方式二
    BX LR
    

    ARM7TDMI Technical Reference Manual 也提到异常服务程序的进入和退出


    注意:异常不同于普通子程序调用,普通子程序调用一般是可预见的,由程序员设置;异常是不可预料的,一般由硬件或OS内核触发。

    • 子程序入口,用寄存器写指令STMFD保存R14和其他寄存器内容到SP
    STMFD SP!,{<register>,LR}
    
    //具体地,如果是保存R0~R7及LR(进栈)
    STMFD SP!,{R0-R7,LR} 
    //其含义是:
    // SP指针变化
    SP = SP - 9x4 //R0~7 + LR,共9个寄存器,而SP默认在高地址位置,往低地址方向移动
    address = SP
    // 寄存器赋值给内存地址的赋值过程
    for i = 0 to 7
      memory[address] = Ri
      address = address + 4
    memory[address] = LR
    
    • 子程序结束,用批量寄存器读取指令LDMFD
      LDMFD是STMFD逆过程,即出栈的过程。
    LDMFD SP!,[<registers>,PC]
    
    // 具体地,将栈内容恢复至PC及R7~R0
    LDMFD SP!,[R0-R7,PC]
    

    1. 当发生异常中断时,应注意保证异常处理程序不会破坏LR,因为LR保存了程序返回地址。异常处理程序返回后,LR内容会写入PC,同时从SPSR中恢复SPSR来实现。

    也就是说,除了子程序(包括异常处理程序)调用时、返回时,其他任何时候,R14可以作为一个通用寄存器。

    程序计数器R15(PC)

    R15保存程序寄存器PC,R15总是指向正在“取指”的指令。

    1. 读R15
    ARM指令集是字对齐的,PC保存下一条指令的地址也应该是4的倍数,因此PC[1:0]总是为0。
    Thumb指令集半字对齐,PC保存的地址是2的倍数,因此PC[0]总是0。

    尽量避免使用STR、STM指令来保存R15,因为不同的芯片使用STR或STM保存R15时,保存的可能是 当前指令地址 + 8byte 或 + 12byte。该偏移,针对具体的芯片是一个常量。

    2. 写R15
    当执行一条写R15的指令时,写入R15的正常结果值被当成一个指令地址,程序从地址处继续执行,相当于执行一次无条件跳转。
    ARM状态下,指令字对齐,写入R15值bit[1:0]必须是0b00,否则结果不可预测;
    Thumb状态下,指令半字对齐,写入R15时将忽略bit[0]。

    当前程序状态寄存器CPSR

    ARM core包含1个CPSR + 5个异常用的SPSR。每种异常模式都有一个对应的SPSR,用于保存异常发生前的CPSR值。CPSR和SPSR都可以用特殊指令MSR、MRS访问(见上文)。

    CPSR与SPSR

    所有模式共享一个CPSR(程序状态寄存器),ARM core通过使用CPSR监视控制内部操作。
    异常模式下,允许访问用于保存CPSR当前值的 SPSR(备份程序状态寄存器),不过每种异常都有相应的SPSR共5个,分别是:SPSR_svc(管理), SPSR_abt(中止), SPSR_und(未定义), SPSR_irq(中断), SPSR_fiq(快速中断)。

    CPSR和SPSR在不同模式下对应寄存器,见下图:

    注:为什么用户模式和系统模式没有SPSR?
    因为用户模式和系统模式不是异常中断,因此没有SPSR。因而在用户模式和系统模式下,不能访问SPSR,否则可能产生不可预知结果。

    CPSR格式

    条件代码标志

    条件代码标志(Condition code flags)包括N, Z, C, V位,可以通过算术运算和逻辑操作设置,也可以通过MSR和LDM指令设置。ARM7TDMI处理器测试这些标志位,以决定是否执行一条指令,这样。
    一般地,如果指令带后缀S,表明指令会修改条件代码标志。不过也有些指令总是改变条件代码标志。

    各标志位含义:

    1. 负标志N 运算结果的第31位值,记录标志设置操作的结果;
    2. 零标志Z 如果标志设置操作的结果为0,则置位;
    3. 进位标志C 记录无符号加法溢出,减法无借位,循环移位;
    4. 溢出标志V 记录标志设置操作的有符号溢出;
      ARM状态中,所有指令都可以按条件来执行;Thumb状态中,只有分支指令可按条件执行。详见ARM Architecture Reference Manual (conditional execution)

    控制标志位

    控制标志位(Control bits)包括I, F, T, M4 ~ M0。

    1. I 中断(IRQ)禁止位;
    2. F 快速中断(FIQ)禁止位;
    3. T 状态位;
    4. M4~M0 处理器模式位;
      发生异常时,控制位改变。特权模式下,可用软件操作这些位。

    中断禁止标志位I和快速中断禁止标志位F
    中断(IRQ)和快速中断(FIQ)是ARM的2个不同模式,本质上来说都是中断,不过FIQ优先级更高,而且FIQ的响应时间也比IRQ更快。发生中断时,FIQ可以插队,如果支持嵌套中断,FIQ可以打断当前正在执行的IRQ处理程序。

    为什么FIQ比IRQ快?
    因为,

    1. FIQ优先级比IRQ更高;
    2. FIQ有自己独有的寄存器(R8~R14,SPSR等),IRQ需要和其他模式共用寄存器,中断现场的保护和恢复会更快;
    3. FIQ在异常向量表的末尾,FIQ中断处理程序紧接着存放,可以直接执行。而异常向量表只能保存IRQ的首地址,发生中断时,进入IRQ中断处理程序需要一次跳转;

    详细可参见ARM中FIQ(快速中断)比IRQ(普通中断)响应快的原因

    中断禁止标志位:

    • I为1时,IRQ中断禁止;为0时,IRQ中断使能;
    • F为1时,FIQ中断禁止;为0时,FIQ中断使能;

    控制位T
    控制位T反应处理器正处于的状态:

    • T为1时,处理器处于Thumb状态;
    • T为0时,处理器处于ARM状态;

    模式控制位M[4:0]
    见下图

    保留位
    CPSR保留位被保留,以便将来使用。当改变CPSR标志位和控制位时,请确认没有改变这些保留位,否则可能会导致未定义行为。


    参考

    [1]周立功, 王祖麟, 陈明计, 严寒亮,等. ARM嵌入式系统基础教程[M]. 北京航空航天大学出版社, 2008.

  • 相关阅读:
    JS的匿名函数和递归应用
    sql server中分布式查询随笔
    Oracle、DB2、SQLSERVER、Mysql、Access分页SQL语句梳理
    db2相关问题及解决方法
    DB2命令大全
    作用域和作用域链浅解析
    css居中的几个实现方法
    选择排序
    ... 语法记录
    call() 与 apply() 和 bind()
  • 原文地址:https://www.cnblogs.com/fortunely/p/15451119.html
Copyright © 2011-2022 走看看