frankfan的胡思乱想

学海无涯,回头是岸

ARM中的状态寄存器

总览☕️

之前内容里我们讨论过armv7架构的指令格式,32bits的前4bits是条件执行相关的标志,需要与状态寄存器CPSR配合使用,今天我们就来聊聊状态寄存器CPSR

CPSRCurrent Program Status Register的缩写,直译为当前程序状态寄存器(这里要注意)

image.png

cpsr编码格式

armv7架构中,cpsr有其非常重要且特殊的意义,因为arm指令编码中是天生带条件执行的,需要与状态寄存器相配合执行指令。

⭐️cpsr寄存器的长度为32bits,其中有一些重要的位:

  • Nbit31,当运算结果为负且运算指令要求更新(指令带s后缀)寄存器时,该位会被置位

  • Zbit30,当运算结果为0且运算指令要求更新寄存器时,该位会被置位

  • ‼️Cbit29,当运算结果产生进位且指令要求更新寄存器时,该位会被置位

    📢这个标志位需要多说几句:

    C(carry) 表示进位,进位表示运算结果需要使用更高的位来保存,比如 5+ 5 = 10,这就产生了进位,鉴于 armv7 架构中寄存器宽度为 32 位,所以最大值是 0xffffffff,当两个数值相加超过 0xffffffff时,将产生进位,此时 CPSR 中的 C bit 被置位,实际上,这个进位的值此时就保存在C位上。

    对于减法而言,C bit 变成了借位,当被减数比减数小就需要借位,比如 3-5,但是C bit的置位是反过来的,当产生借位时,C bit0,否则 C bit1,也就是 3-5 时 C bit 为0,5-3 C bit 为 1。实际上这是可以被理解的,在计算机中负数用补码表示,1-2实质为1+(-2),表示为二进制则为0x1+0x0xfffffffe结果为0xffffffff,此时并没有产生进位,所以C位不会置1;而当2-1时实质为2+(-1),表示为二进制则为0x2+0xffffffff,此时产生了进位,则C位置1;所以在对待C位的设置逻辑上,加法与减法的本质都是一样的,都是保存运算结果的进位值。

  • ‼️Vbit28,当运算结果产生符号位溢出且指令要求更新寄存器时,该位会被置位

    📢这个标志位需要多说几句:

    所谓的符号位溢出,是指发生这样的运算时:正+正=负负+负=正;因为计算机中所有的运算都是定长运算,因此运算结果不可避免的存在超出定长长度这种情况,这就是所谓的溢出了。

    那么,V位的结果最终是0还是1,是怎么运算得来的呢?手册公式如下:

    sign_sum = Sint(x)+Sint(y) #Sint表【有符号短整型】
    result = sign_sum<32-1:0>
    overflow = if Sint(result) == sign_sum then '0' else '1'
    
    不得不说这个公式颇为费解

    举例说明:现有2个单字节(8bits)大小的数据(有符号数),X、Y;

    🔖X = -1Y = -2,根据公式:

    1.sign_sum = Sint(-1)+Sint(-2) => -1+-2 =>-3
    2.result = -3<7:0> = -3
    3.Sint(result) => Sint(-3) => 0xfd
    

    显然,有符号短整型Sint(-3))此时的十六进制数0xfd就是十进制的-3,因此Sint(-3)等于sign_sum,因此overflow的值为0

    🔖当X = 127、Y = 2,根据公式:

    1.sign_sum = Sint(127)+Sint(2) => 127 + 2 =>129
    2.result = 129<7:0> => 129 =>0x81
    3.Sint(result) => Sint(129) => -2
    

    显然,-20x81并不相等,因此overflow的值为1

    🔖当X=-127、Y=-1,根据公式:

    1.sign_sum = Sint(-127)+Sint(-2) => -127 + -2 =>-129
    2.result = -129<7:0> => -129 =>0x81
    3.Sint(result) => Sint(-129) => 2
    

    显然,20x81并不相等,因此overflow的值为1


  • Qbit27,累积饱和位,置为1表示某些指令中发生溢出或饱和,通常与数字信号处理(DSP)有关。

  • J:bit24,指示处理器当前是否处于 Jazelle 状态;这个状态用来直接硬件(CPU)运行java字节码的,但效率始终要打折扣(我们一般不关心)

  • bit[23:20],保留位。

  • 📌GE[3:0](4字节)bit[19:16],大于或者等于标志位,主要被SIMD指令使用SIMD 全称为 single instruction multiple dataarmv7 提供一条指令同时处理多个寄存器数据,属于扩展指令(一切为了效率...额)

  • Ebit9,指示当前处理器是运行于大端模式还是小端模式,同时,也可以通过设置该位来切换大小端模式。(CPU大小端模式是可以通过设置状态寄存器中的E位来切换的)

  • 📌mask bitsbit[8:6]屏蔽A(abort)、I(interrupt)、F(fast interrupt),分别对应异步终止、中断和快中断,当对应的位为1时,相应的功能被屏蔽,当处理器需要屏蔽中断时,通常就是设置该屏蔽位,当这些位被设置为1时,意味着相应的功能被屏蔽(用户模式下无权修改这些位)。

  • 📌Tbit5,指示处理器当前使用 thumb 指令集还是 arm 指令集,当前位和 J bit决定当前处理器的指令集,是 arm、Thumb、Jazelle 还是 ThumbEE 指令集。J、T的值对应指令集关系为:00-arm指令集01-Thumb指令集10-Jazelle指令集11-ThumbEE指令集(所谓ThumbEE指令集其实是thumb2指令集的加强版,在其基础上针对性的增强了动态生成代码功能的支持);所以通常如果T位被置为1就可以认为是Thumb指令集(无论是thumb1还是thumb2),但是如果T位不是1就能否一定说明是arm指令集呢?严格来说是不行的,还需要关注J位是否为1,只有当J位也不为1时才说明当前是arm指令集

  • ⭐️Mbit[4:0],模式位,指示处理器当前位于哪种运行模式下;这个是需要关注的,

    armv7 架构有多种(9种「用户模式在内」模式代表不同的系统操作权限:

    image.png
    ARM-CPU的几种工作模式

    工作在用户模式(User)下的功能是「受限的」,体现在状态寄存器上就是,有些状态寄存器的位是不被允许设置的,此时的CPSR是受限的,被称为APSRApplication Program Status Register

    image.png

    APSR状态寄存器

    相较于CPSR状态寄存器,APSR寄存器的一些标志位被重新解释或者🈲访问。

    比如bit[26:24] 被修改成了RAZ/SBZP 位,这个位置是一个比较「奇怪」的设定,armv7提供一种方式,可以不遵循传统的「读、改、回写」顺序而使用指令msr直接写APSR的高8bits,尽管基本也不会这出这样的迷之操作(谁会去手动的方式修改这些标志位呢),而只有将RAZ/SBZP位置为0,才能修改成功。(而事实可以认为毫无卵用🐑)

    此外APSR相较于CPSR一个大不同是低2字节,在CPSR中,最后的5bit就是用来控制CPU的模式的。armv7架构有9种不同的工作模式,与对应的M位bits[4:0])关系是:

    image.png

    arm架构将3个权限分布在9个模式中,其中用户模式User是最低权限,在User模式下是无法操作这些模式位从而改变当前这个User模式的。User模式位于PL0层,进入到PL1层需要调用svc指令;

    而对于其他本来就处于 PL1 级别权限而言,更改处理器模式可以直接设置 CPSR 中对应的状态位,arm 为访问状态寄存器提供了特定的指令,mrs 和 msr(显然,这样的指令对于User级别权限是没啥用处的,即便User权限能通过指令操作APSR的高5bits,而又有什么什么场景需要手动修改那些值呢)。

    ✏️m:move(移动),r:register(通用寄存器),s:special(特定寄存器);因此mrs这条指令的意思就是「将特定寄存器中的内容移动到通用寄存器中」,而这个「特定寄存器通常就是指状态寄存器」;而msr则是反过来,「将通用寄存器中的值移动到特定寄存器」,所以这两条指令有点类似对状态寄存器做「读写」操作。

    image.png
    PL1权限下的模式切换引起状态寄存器值的保存

    😴所谓的CPSP中的C表示Current,语义是「当前的~」,而SPSR中的第一个字母S则表示Saved,在处理器发生中断或者异常时,自动从一个模式跳转一个模式下,而「原模式」下的 cpsr/apsr 将会被自动保存在「目标模式」的 spsr 中,通常异常处理程序需要获取原模式下的 cpsr 寄存器信息(因为模式的切换并不能打断执行的时序流程),那么模式切换的过程是怎么发生的呢?

    当需要切换模式时:

    1、将需要切换的模式位设置先保存到 spsr

    2、执行 movs 指令

    mov 指令的后缀 s 在 arm 中有两种意思,如果目标寄存器为非 pc,它的隐含操作为当前执行的操作结果会更新状态寄存器,如果目标寄存器为 pc,它的隐含操作为将 spsr 中的值赋值给 cpsr,通常使用这个特性执行模式切换
    
    msr spsr_cxsf, ${target_mode_bits}#target_mode_bits将要设定的目标比特位的值                        
    #other codes
    movs pc, lr #这里的意思并非是简单的将lr中的值给到pc,因为movs操作的目标寄存器是pc,因此这里的意思是将spsr中的值赋值给cpsr,这是就完成了模式的切换。(因为在target_mode_bits中已经设计好了模式的值,先保存到spsr状态寄存器,然后再保存到cpsr寄存器)
    

    spsr_cxsf寄存器中带有的后缀cxsf分别表示:

    • ccpsr[7:0],控制位域,中断控制、模式位控制位
    • xcpsr[15:8],扩展位域
    • s:cpsr[23:16],状态位域
    • fcpsr[31:24],条件标志域,主要包括 N、Z、C等条件标志码

posted on 2021-12-27 23:55  shadow_fan  阅读(1049)  评论(0)    收藏  举报

导航