【MIPS CPU 体系结构概述1】连载6:

K0 and K1 寄存器

这个两个寄存器是被操作系统核心使用的暂时变量,从而不需要使用一些内存变量。读者 如果有兴趣的话,可以发现gcc编译器的ABI不会使用这两个寄存器。换句话
说,K0和K1是系统保留的。

在使用这两个寄存器的时候,要非常小心。例如,当在异常中断处理的中后期,系统软件 通常会开启中断,从而系统可以支持嵌套中断处理。这个时候,软件要注意K0和K1的保 存和恢复工作。

笔者不鼓励读者使用MIPS的AT寄存器。应该使用.set noat宏来关闭编译器的优化。 流水线(Pipeline) 和中断
读者知道,MIPS是一个RISC技术处理器。在某一个时刻,在流水线上,同时有若干个指 令被处理在不同的阶段(stage)上.
MIPS处理器一般采用5级流水结构。

IF RD ALU MEM WB

那么读者要问:当一个中断异常发生时,CPU到底该如何handle?答案是这样的:

“On an interrupt in a typical MIPS CPU, the last instruction to be completed before interrupt
processing starts will be the one that has just finished its MEM stage when the interrupt is detected. The exception victim will be the one that has just finished its ALU stage...”
对上述的理解是这样的:CPU 会保证完成那条已通过 MEM流水级的指令。然后将中断牺 牲者(exception victim)定位在后面那条(following)指令上。要注意的是:我们是在谈中断 (Interrupt), 而不是异常(Exception). 在MIPS中,这是有细微区别的。

下面介绍几个重要的SR(Status Register,状态寄存器)与异常和中断有关的位。

* SR[EXL]
Exception Level; set by the processor when any exception other than Reset, Soft Reset, NMI, or Cache Error exception are taken. 0: normal 1: exception

当EXL被置位时,
- 中断是被禁止的。 换句话说,这时SR[IE]位是不管用了,相当于所有的中断都被屏蔽
了。
- TLB Refill异常将会使用General Exception Vector而不是缺省的TLB Refill Vector.
- 如果再次发生异常,EPC将不会被自动更新。这一点要非常注意。如果想支持嵌套异 常,要在异常处理例程中清EXL位。当然要先保存EPC的值。另外要注意的:MIPS当陷 入Exception/Interrupt时,并不改变SR[UX],SR[KX]或SR[SX]的值。SR[EXL]为1自动的 将CPU mode运行在核心模式下。这一点要注意。

* SR[ERL]
Error Level; set by the processor when Reset, Soft Reset, NMI, or Cache Error exception are taken. 0: normal 1: error
当ERL被置位时,

- 中断被禁止。
- 中断返回ERET使用的是ErrorEPC而不是EPC。需要非常注意这个区别。
- Kuseg和xkuseg 被认为是没有映射(Mapped)的和没有缓存(Un-Cached)。可以这样理
解,MIPS CPU只有在这个时刻才是一种**实模式(real mode)**,可以不需要TLB的映射, 就直接使用kuseg的地址空间。

* SR[IE]
Interrupt Enable 0: disable interrupts 1: enable interrupts。请记住: 当SR[EXL]或SR[ERL]被SET时, SR[IE]是无效的。

* Exception/Interrupt优先级。

Reset (highest priority)
Soft Reset
Nonmaskable Interrupt (NMI)
Address error --Instruction fetch
TLB refill--Instruction fetch
TLB invalid--Instruction fetch
Cache error --Instruction fetch
Bus error --Instruction fetch
Watch - Instruction Fetch
Integer overflow, Trap, System Call, Breakpoint, Reserved Instruction, Coprocessor Unus-able, or Floating-Point Exception Address error--Data access
TLB refill --Data access
TLB invalid --Data access
TLB modified--Data write
Cache error --Data access
Watch - Data access
Virtual Coherency - Data access
Bus error -- Data access
Interrupt (lowest priority)

读者请注意,所谓的优先级是指:当在某个时刻,同时多个异常或中断出现时,CPU将会 按照上述的优先级来处理。如果CPU目前已经在TLB refill处理的例程中,这时,出现了总 线错(Bus Error)的信号,CPU不会拒绝。当然,在这次的处理中,EPC的值不会被更 新,如果EXL还是处于被置位的状态。

异常的嵌套
在有的情况下,希望在异常或中断中,系统可以继续处理其他的异常或中断。 这需要系统软件处理如下事情:
*进入处理程序后,我们要设置CPU模式为核心态,然后清除SR[EXL],从而支持EPC会被 更新,从而支持嵌套处理。

* EPC 和SR的值

EPC和SR寄存器是两个全局的。任何一个异常和中断发生时,CPU硬件都会
将更新上述寄存器的当前值。所以,对于支持异常嵌套的系统,要妥善保存EPC和SR寄 存器的值。

*SR[IE]是一个很重要的位来处理嵌套异常。值得注意的,或容易犯错的一点是:
在做恢复上下文时,要避免重入问题。比如,要用eret返回时, 要建立EPC的值。在此之 前,一定要先关闭中断disable interrupt. 否 则,EPC可能被冲掉。

下面是一段异常中断返回的例子代码:

/* 读取SR的当前值*/
mfc0 t0,C0[SR]
/*加一个delay slot指令 */
nop
/* 清楚SR[IE],关闭中断 */
li t1,~SR[IE]
and t0,t0,t1
mtc0 t0,C0[SR]
nop
/* 可以安全的恢复EPC的值*/
ld t1,R_EPC(sp)
mtc0 t1,C0[EPC]
nop
lhu k1, /* 恢复老的中断屏蔽码,被暂时保留在k1里*/

or t0,t0,k1
/*从新对SR[EXL]置位。ERET会自动将其清除。一定要理解 ,为什么中断例程要在前面 要清除 EXL。如果不的话。就不能支持嵌套异常。为什么,希望读者能思考并回答。并 且,在清EXL之前,我们一定要先把CPU模式变为核心模式。*/
ori t0,t0,SR[EXL]
/*一切就绪,恢复中断屏蔽码和对EXL置位*/
mtc0 t0,C0[SR]
nop
ori t0,t0,SR[IE]
/* 置为IE */
ori t0,t0,SR[IMASK7 ]
mtc0 t0,C0[SR ]
nop
/*恢复CPU模式 */
ori t0, t0,SR[USERMODE]
mtc0, t0, C0[SR ]

eret
/*eret将对EXL清零。所以要注意,如果你在处理程序中改变了CPU的模式,一定要确
保,在重新设置EXL位后,恢复CPU的原来模式,否则用户进程将会在核心态下运行。

--电子创新网--
粤ICP备12070055号