mips 微系统
CP0协处理器
CPU 控制寄存器
寄存器助记符 | 寄存器编号 | 描述 |
---|---|---|
SR | 12 | State Register |
Cause | 13 | 记录异常中断的原因 |
EPC | 14 | Exception program counter发生异常和中断后从哪里重新开始执行 |
SR
这里我们实际使用到的或者说有意义的只有
IM——SR[15:10]
其实这里应该指的是SR[15:8]的这8位,其中IP1-0也就是SR[9:8]是由CPU内部产生的
- 中断屏蔽:一个8位的域定义哪些允许中断源活动时产生异常。其中6个中断源由CPU核外部的信号产生。其余两个是Cause寄存器中软件可写的中断位
EXL——SR[1]
- 异常级:任何异常发生时置位,这会强行进入核心态并禁止中断:目的是吧EXL位维持足够长的时间以便软件决定新的CPU特权级和中断屏蔽该设成什么
IE——SR[0]
- 全局的中断使能位:注意不管这位是什么值,EXL和ERL总是禁止所有的中断
Cause
BD——Cause[31]
-
分支延迟:EPC保存的是异常处理完之后的返回地址,正常情况下,这也指向异常受害指令。
-
但是如果发生异常的指令是在一条转移指令的延时槽里,EPC得指向那条转移指令:重新执行转移指令没有- 什么害处,但是如果返回到延迟槽指令本身,转移就不会发生,从而这个异常将破坏被中断的程序。
-
只要异常发生在延迟槽的指令,Cause(BD)就会置为,EPC就会指向分支指令。如果想要分析异常受害指令,只要看看Cause(BD)(如果Cause(BD)==1,那么该指令位于EPC+4)就知道了。
IP——Cause[15:10]
这里其实也是IM一个道理
待决的中断:这里表示待发生的中断。IP照抄CPU硬件的输入信号,IP1-0
(软件中断位)可读可写包含你最近写入的值。
- 当相应的
SR(IM)
位(还要受到其它禁止中断的条件约束)允许时,这八位中的任意以为活动都会导致一个中断
BD——Cause[6:2]
这是一个5位的编码,告诉你发生了哪种异常。
ExcCode | 助记符 | 指令与指令类型 | 描述 |
---|---|---|---|
0 | Int | 所有指令 | 中断 |
4 | AdEL | 所有指令 load型指令(或特指其中某型) |
(取数,取指或者存数时)地址错误: PC地址未字对齐 PC地址超过0x3000-0x6ffc (取数,取指或者存数时)地址错误: lw:取数地址未与4字节对齐 lh:取数地址未与2字节对齐 lh,lb:取Timer |
5 | AdES | store型指令 | (取数,取指或者存数时)地址错误: sw:存数地址未4字节对齐 sh:存数地址未2字节对齐 sh,sb:存Timer寄存器的值 store型指令: 计算地址加法溢出 向计时器的Count寄存器存值 存数地址超过DM,Timer0,Timer1,中断发生器的范围 |
8 | Syscall | syscall | 系统调用,执行了一条syscall指令 |
10 | RI | 出现未知的指令码 | |
12 | Ov | add,addi,sub | 算数溢出 |
EPC
异常返回地址寄存器。这是一个博爱村异常返回点的寄存器。导致(或者遭受)异常的指令地址存入EPC,除非Cause寄存器中的BD位置位了,这种情况下EPC指向前一条(分支)指令
CPU控制指令
指令 | 格式 | 描述 |
---|---|---|
mtc0 | s,<n> | 把数据传送到CP0 把CPU通用寄存器s中的内容传送到CP0的寄存器n 数据为32位 |
mfc0 | d,<n> | 从协处理器中取出数据 通用寄存器d中装入CPU控制寄存器n的值 这是查看控制寄存器的值的唯一方式 |
关于mfc0
想要更新控制寄存器中的单个域——比如说——状态寄存器SR
mfc0 t0, SR
and t0, <要清零的为的反码>
or t0, <要置1的位>
mtc0 SR, t0
这里有一个比较抽象的话后续再来理解一下
即返回到用户态和改变特权级的操作必须是同步的,不可分的(原文只讲了不可分的,我的理解就是同步的进行操作)
用软件触发的异常——异常调用——作为用户代码请求(运行在高特权级上的)操作系统内核服务的唯一机制。
什么时候需要用到哪些寄存器
这里是针对CP0中的控制寄存器而言的
上电后:
设置SR来使CPU进入一个可工作的状态
处理任意异常:
-
早期:调用一个固定入口地址的公共的“通用异常处理程序”
-
自那以后:对不同目的使用分开的异常处理程序
在异常入口处:不保存任何程序寄存器,只有返回地址被存在EPC中。
从异常返回:
- 控制最终必须返回到异常入口处保存到EPC中的地址。
- 不管是什么异常,返回时都需要报SR寄存器调整回原来的值,恢复用户态特权、允许中断以及消除异常的一般影响
- 异常返回指令eret合并完成了返回用户空间和复位SR(EXL)的功能
中断:
SR用来调整中断掩码(掩码就是一串二进制码,掩码的作用是用来存储和操作“状态”)
纯粹为了引发异常的指令:
比如break
和syscall
异常、中断及初始化
- 外部事件:在CPU核之外的时间——即来自于真实的“连线”上的输入信号,这就是中断。
- 存储器地址转换异常
- 程序或硬件检测到的错误:这些包括不存在的指令、在用户权限下非法的指令、在相应SR位被禁止是执行的协处理器指令、整数溢出、地址对齐出错、用户态中访问kuseg以外的地址
- 系统调用和自陷
精确异常
也就是我们的宏观pc的来由,如果某个pc是异常受害指令,那么我们希望在这个指令之前的指令已经全部处理完成,在这个指令之后的还没有开始处理。
全部内容如下:
- 明确的罪证:在任何异常之后,CPU的控制寄存器EPC都指向一个正确的地方,异常处理之后从该处开始重新执行。在大多数情形中,EPC指向异常受害指令,但是如果异常受害指令处于分支延迟槽内,则EPC指向前面的分支指令:返回到分支指令去重新执行受害指令,但是返回到受害指令将导致分支被忽略。
- 当受害指令处于分支延迟槽内时,原因寄存器的Cause(BD)位置位
- 异常出现在指令序列中:由于是流水线,而且在不同的流水级都有可能会出现问题,但是我们为了实现精确异常,不应该是出现异常就处理,也就是出现第二条指令的异常事件先发生时需要先处理第一条指令
- 为了避免这一个问题,早期发现的异常并不立即采取措施:该事件只是被记录并沿着流水线传递。在大多数CPU设计中,指定一个特定的流水线阶段作为检测异常的地方。如果当我们的异常记录正沿着流水线向下传递,更老的指令的后期检测到的事件到达了这个终点线,此时异常记录就直接丢弃。
- 后续指令无效:因为流水线的原因,处于EPC中的受害指令之后的指令就已经开始了。
非精确异常
这里实际上指的是历史上的MPIS CPU的乘法器,也就是我们P6的内容,采取直接发送一个busy信号的处理方法,这里我们不在进行讨论
异常发生的时机
因为异常是精确的,那么异常发生的时间应当也是没有歧义的:
- 异常之前执行的最后一条指令就是异常受害指令的前一条。
- 如果该异常不是中断:受害指令即是引发异常的指令
下面是MIPS CPU决定处理一个异常是所要做的
- 设置EPC指向重新开始的地址
- 设置SR(EXL)位,强制CPU进入内核态(高特权态)并且禁止中断
- 设置Cause寄存器这样软件可以看到发生异常的原因。在地址异常时,BadVAddr也要设置但是我们课程好像没有这个要求
- 然后CPU开始从异常入口点取值,此后一切交给软件处理。其实也就是继续进行handler处理程序的执行部分