深入浅出MIPS 三 MIPS的协处理器CP0

在MIPS体系结构中,最多支持4个协处理器(Co-Processor)。其中,协处理器CP0是体系结构中必须实现的。它起到控制CPU的作用。MMU、异常处理、乘除法等功能,都依赖于协处理器CP0来实现。它是MIPS的精髓之一,也是打开MIPS特权级模式的大门。
MIPS的CP0包含32个寄存器。关于它们的资料可以参照MIPS官方的资料MIPS32(R) Architecture For Programmers Volume III: The MIPS32(R) Privileged Resource Architecture的Chap7和Chap8。本文中,仅讨论常见的一些寄存器。
Register 0: Index,作为MMU的索引用。将来讨论MMU和TLB时会详解之。
Register 2, EntryLo0,访问TLB Entry偶数页中的地址低32Bit用。同上,在MMU和TLB的相关章节中详解。
Register 3, EntryLo1,访问TLB Entry奇数页中的地址低32Bit用。
Register 4, Context,用以加速TLB Miss异常的处理。
Register 5, PageMask,用以在MMU中分配可变大小的内存页。
Register 8, BadVAddr,在系统捕获到TLB Miss或Address Error这两种Exception时,发生错误的虚拟地址会储存在该寄存器中。对于引发Exception的Bug的定位来说,这个寄存器非常重要。
Register 9, Count,这个寄存器是R4000以后的MIPS系统引入的。它是一个计数器,计数频率是系统主频的1/2。BCM1125/1250,RMI XLR系列以及Octeon的Cavium处理器均支持该寄存器。对于操作系统来说,可以通过读取该寄存器的值来获取tick的时基。在系统性能测试中,利用该寄存器也可以实现打点计数。
Register 10,EntryHi,这个寄存器同EntryLo0/1一样,用于MMU中。以后会详述。
Register 11,Compare,配合Count使用。当Compare和Count的值相等的时候,会触发一个硬件中断(Hardware Interrupt),并且总是使用Cause寄存器的IP7位。
Register 12,Status,用于处理器状态的控制。
Register 13,Cause,这个寄存器体现了处理器异常发生的原因。
Register 14,EPC,这个寄存器存放异常发生时,系统正在执行的指令的地址。
Register 15,PRID,这个寄存器是只读的,标识处理器的版本信息。向其中写入无意义。
Register 18/19,WatchLo/WatchHi,这对寄存器用于设置硬件数据断点(Hardware Data Breakpoint)。该断点一旦设定,当CPU存取这个地址时,系统就会发生一个异常。这个功能广泛应用于调试定位内存写坏的错误。
Register 28/29,TagLo和TagHi,用于高速缓存(Cache)管理。

下面,我们来详解CP0中常用的几个寄存器,它们是:BadVAddr,Count/Compare,Status/Cause,EPC,WatchLo/WatchHi。

BadVAddr: 错误的虚拟地址。实际上,这个寄存器仅限于出现TLB Miss和ADE (Address Error)两种异常的时候,才能用到。发生错误的虚拟地址会放在这个寄存器里。
一般地,在设定TLB时,通常将0地址附近的一块,设定为无映射区域。这样,一旦编程时不慎访问了空指针(0地址),或是空指针加上一定的偏移量,那么,系统就会抛出一个TLB Miss Exception。在这种情况下,发生错误的地址会被记录在BadVAddr寄存器中。一般地,这个地址是一个非常接近于0的地址。往往地,通过BadVAddr在寄存器中的值,和相关数据结构的分析,就可以找出对应的语句。
另外,对于ADE异常,异常地址也会被保存在BadVAddr中。一般地,操作系统会自行接管这个地址,分两次读取/写入这个地址处的数据,而不会发生Core Dump的情况。但是,如果这个地址既属于非对齐地址,又属于TLB Miss,那么,系统还是会抛出一个Core Dump的。正常地,操作系统应当正确处理这个异常,如果在Exception Handler中发现地址在TLB中未映射,还是应当抛出ADE异常,而不是TLB Miss。

Count/Compare: 这两个寄存器是CP0中的一对欢喜冤家。Count是一个计数器,每两个系统时钟周期,Count会增加1,而当它的值和Compare相等时,会发生一个硬件中断(Hardware Interrupt)。这个特性经常用来为操作系统提供一个可靠的tick时脉。

Status: 这个寄存器标识了处理器的状态。其中,中断控制的8个IM(Interrupt Mask)位和设定处理器大小端的RE(Reverse Endianess)位。8个IM位,分别可以控制8个硬件中断源。它们将在讲述‘硬件中断’时详解。RE位很有趣,设定这个Bit可以让CPU在大端(Big Endian)和小端(Little Endian)之间切换。默认情况下,MIPS处理器是大端的,和网络序相同。但是,为了能在MIPS上运行类似Windows NT的服务器操作系统,设定这个Bit可以令处理器工作在Little Endian模式下。
Cause: 在处理器异常发生时,这个寄存器标识出了异常的原因。其中,最重要的是从Bit2到Bit6,5个Bit的Excetion Code位。它们标识出了引起异常的原因。具体数值代表的异常类型,如下所示:
0: Interrupt,中断;
1: TLB Modified,试图修改TLB中映射为只读的内存地址;
2: TLB Miss Load,试图读取一个没有在TLB中映射到物理地址的虚拟地址;
3: TLB Miss Store,试图向一个没有在TLB中映射到物理地址的虚拟地址存入数据;
4: Address Error Load,试图从一个非对齐的地址读取信息;
5: Address Error Store,试图向一个非对齐的地址写入信息;
6: Instruction Bus Error,一般是指令Cache出错;
7: Data Bus Error,一般是数据Cache出错;
8: Syscall,由syscall指令产生。操作系统下,通用的由用户态进入内核态的方法。可以类比IA32的“调用门”理解;
9: Break Point,由break指令产生。最常见的bp指令,是由编译器产生的,在除法运算时插入一个break point指令,以达到在除0时抛出错误信息的目的。因此,如果在定位问题时发现了一个Break Point异常,且它的异常分代码为07,应当考虑是出现了除0的情形;
10: RI,保留指令。在CPU执行到一条没有定义的指令时,进入此异常;
11: Co-processor Unavilible,协处理器不可用。这个异常是由于试图对不存在的协处理器进行操作引起的。特别的,在没有浮点协处理器的处理器上执行这条命令,会导致这个异常。随之,操作系统会调用模拟浮点的lib库,来实现软件的浮点运算;
12: Overflow,算术溢出。只有带符号的运算会引起这个异常;
13: Trap,这个异常来源于trap指令。和syscall指令类似地,trap指令也会引起一个异常,但trap指令可以附带一些条件,这样可以用于调试程序用。
14: VCEI,指令高速缓存中的虚地址一致性错误。(没明白怎么回事,还有待高手补充)
15: Float Point Exception,浮点异常;
16: Co-processor 2 Exception,协处理器2的异常;
17~22,留作将来的扩展;
23: Watch,内存断点异常。当设定了WatchLo/WatchHi两个寄存器时起作用。当load/store的虚拟地址和WatchLo/WatchHi中匹配时,会引发这样一个异常;/* 这个地方经典著作《See MIPS Run》犯了一个错误,将虚拟地址写成了物理地址 */
24~30,留作将来的扩展;

EPC: 这个寄存器的作用很简单,就是保存异常发生时的指令地址。从这个地方可以找到异常发生的指令,再结合BadVAddr, sp, ra等寄存器,就可以推导出异常时的程序调用关系,从而定位问题的根因。一旦异常发生时EPC的内容丢失,那么对异常的定位将是一件非常困难的事情。
WatchLo/WatchHi: 这一对寄存器可以用来设定“内存硬件断点”,也就是对指定点的内存进行监测。当访问的内存地址和这两个寄存器中地址一致时,会发生一个异常。为了适应64Bit的一些扩展功能,某些MIPS处理器又对这两个寄存器的功能做了一些修改,与MIPS体系结构的定义已经有了差别,如RMI的多核处理器等。

于协处理器CP0的访问,需要使用特别的指令。这些指令属于“特权级指令”,只有在内核态(Kernel Mode)下才能执行。如果在用户态下,会引起一个异常(Exception)。
对CP0的主要操作有以下的指令:
mfc0 rt, rd 将CP0中的rd寄存器内容传输到rt通用寄存器;
mtc0 rt, rd 将rt通用寄存器中内容传输到CP0中寄存器rd;
mfhi/mflo rt 将CP0的hi/lo寄存器内容传输到rt通用寄存器中;
mthi/mtlo rt 将rt通用寄存器内容传输到CP0的hi/lo寄存器中;
当MIPS体系结构演进到MIPS IV的64位架构后,新增了两条指令dmfc0和dmtc0,向CP0的寄存器中读/写一个64bit的数据。

前面提到,MIPS体系结构是一个无互锁,高度流水的五级pipeline架构,这就意味着,前一条指令如果尚未执行完,后一条指令有可能已经进入了取指令/译码阶段。这样,就有可能发生所谓的CP0冒险(CP0 Hazard)现象。简单地说,就是mfc和mtc指令的执行速度是比较慢的,因此,开始执行完下一条指令时,有可能CP0寄存器的值尚未最后传输到指定的目标通用寄存器中。此时,如果读取该通用寄存器,有可能并未得到正确的值。这就是所谓的CP0冒险现象。
为了避免CP0冒险,我们在编程时需要在CP0操作指令的后面加上一条与前一条指令的目的通用寄存器无关的指令,也就是所谓的延迟槽(delay slot)。如果对性能不敏感,可以考虑用一条nop空操作指令填充延迟槽。
例如,经常在异常处理例程(exception handler)中出现的内容:

....
mfc0 k0, $cause
nop /* mfc0指令执行速度慢,在延迟槽中加一个空操作 */
mov t0, k0 /* 将cause寄存器内容放到t0,进行下一步操作 */

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
英国科学家 Dominic Sweetman(经典著作 See MIPS Run 的作者),称 MIPS 为“高效的 RISC 体系结构中最优雅的一种体系结构”。 它是一个双关语: 即是 Microcomputer without Interlocked Pipeline Stages 的缩写,同时又是 Millions of Instructions Per Second 的缩 写。 MIPS 的处理单元是一个五级流水线:Instruction Fetch, Register & Decoder, ALU, Memory 以及 Write back。一开始的 MIPS 是为 32 位系统设计的,实际上,后续的 64 位扩 展,也依然对 32 位的工作模式向下兼容着。一如其他的 RISC 处理器,MIPS 的每条指令长度 是固定的 32bit。(因此,最长的局部跳转指令只能跳转 2 的 26 次方 Byte,也就是 2 的 24 次 方,16777216 条指令) MIPS 有 32 个通用寄存器,编程者可以使用其中除$0 外的所有寄存器暂存数据。$0 寄存 器,在硬件上被设计为永远读出 0。我们可以用$0 寄存器的此特性,实现一些技巧性的编程, 譬如实现 NOP 操作。MIPS 本没有 NOP 指令,但由于对$0 寄存器的写入实际上无意义,可以 作为空操作使用。 事实上,编译器从高级语言(典型如 C/C++)转换为 MIPS 汇编指令时,一般总是遵守一 定的寄存器使用约定。某些寄存器用来从函数中传入和传出参数,存储临时数据,另一些则起特 殊作用,如保存调用函数时的指令地址,或作为堆栈指针等。如果你使用汇编开发,理论上可以 无视这点约定,但是,一般地,遵守这个约定,与人方便,也为己方便。关于寄存器使用的约定, 以后会展开论述。 一如所有的 RISC 处理器,MIPS 没有 CISC 那样复杂多变的寻址方式,统一为 Load/Store 寻址。任何载入和存储操作,都可写为如下形式: lw $1, offset ($2) 这条指令的操作符可以为 Load 或 Store,一次 Load/Store 操作的范围可以为字/半字/ 字节(对应 gcc 的 int, short 和 char)。偏移量是一个带符号的 16bit 整数。两个作为操作数 的寄存器可以是任何通用寄存器。(你可以向$0 写入,但无任何意义,等同于空操作)。对于 64 位模式下,也可以对 double 类型进行操作。注意 Load/Store 都必须对应一个对齐的地址,否 则会引发一个异常(Exception)。 MIPS 支持最多 4 个协处理器协处理器 CP0 为 CPU 的控制协处理器,是体系结构中必须 实现的。CP1 为浮点处理器。CP2 保留,各生产厂商往往用来实现一些自己的特色功能,例如 RMI 的 Fast Message Ring 等。CP3 原本也是保留共扩展用,但很多 MIPS III 和 MIPS IV 时代的扩展指令集使用了它。对于 CP0,我们会有专门的一段用来讨论。 为适应处理器向多核时代的演进, MIPS 引入了多核操作必要的原子指令 (Atomic operation)、内存屏障(Barrier)等操作。在 SMP 或 AMP 等多核架构中,这些指令是并行计算 同步的保障。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值