简单的异常处理机制

NEMU中的异常处理

作为A阶段的第一部分内容,我们需要了解和实现简单的异常处理机制。 RISC-V中,将中断和异常统称为例外,也就是程序在正常执行过程中的强制转移。 因此,在本节内容中,除了异常处理机制之外,我们还会简要介绍计时器中断的相关内容。

产生例外的原因有很多,有一些例外是主动触发的,例如系统调用; 有一些例外是被动触发的,例如外部中断和计时器中断。 RISC-V的特权体系结构将特权级划分为Machine、Supervisor和User这3个层级。 Machine态用于BIOS等底层环境。Supervisor态用于操作系统,User态则用于普通的用户程序。 针对RISC-V指令集,如果一些嵌入式系统不需要3个级别,那么也可以不实现Supervisor态,只使用User和Machine这两个状态。 在一生一芯计划中,大家只需要实现M态,当然,我们也欢迎大家积极探索更多的相关知识,实现S态和U态。

在一生一芯计划中需要实现的相关系统调用和计时器中断都需要操作CSR寄存器。CSR寄存器大致可以分为例外触发相关的寄存器和例外处理相关的寄存器这两类。 大家可以阅读PA讲义在新窗口中打开The RISC-V Instruction Set Manual Volume II: Privileged Architecture在新窗口中打开以了解更多的相关信息。

  • 例外的触发:当发生异常时,处理器需要将发生异常的地址放入mepc寄存器,并跳转到mtvec中存放的地址,该地址也就是中断处理函数的入口。
  • 例外的处理:当处理器跳转到mtvec中存放的地址,即中断处理函数的入口后,软件需要根据CSR中的mcause寄存器完成对例外种类的确定,并根据不同种类的例外跳转到相应的例外处理函数的入口。最后,相应的例外处理函数具体地处理某个例外。
  • 例外的返回:例外的返回通过mret指令进行。当例外发生时,处理器将发生例外的地址保存到mepc寄存器,之后跳到例外处理入口。当例外处理结束后,通过mret指令返回到mepc所指向的地址,也就是例外发生前的地址。

什么时候需要+4?

在PA讲义里提示我们需要在合适的地方对保存的PC加上4,但对于系统调用,外部中断,计时器中断等例外而言,都需要对PC加4吗,为什么?

完成PA3.1

根据PA讲义完成以下内容:

直到你看到如下提示框:

温馨提示

PA3阶段1到此结束.

NPC中的异常处理

在PA中我们已经了解了简单的异常处理机制,自然是时候应用在我们的NPC中了。 在支持RV64IM的单周期NPC中,我们已经搭建了面向riscv64-npc的运行时环境,同时为NPC搭建了基础设施,相信大家已经很熟悉这些流程了。 不过,为了使DiffTest支持我们在本节新增的异常处理机制,我们还需要实现nemu/src/cpu/difftest/ref.c中的difftest_raise_intr()这个API。

在NPC中实现简单的异常处理机制

进入PA3,系统的复杂度开始逐渐上升,我们也接触到越来越多的抽象层。 一生一芯是一个培养性的项目,讲义中的指导和提示其实已经足够,需要大家认真阅读、耐心理解。 如果遇到看上去难以理解的问题,记得多求助手册在新窗口中打开

编写自己的测试程序

在AM已经有一些针对异常处理相关的测试程序,大家可以尝试在NEMU和NPC中运行这些测试程序,检查自己的实现是否会出现问题。

不过,AM已经给我们提供了如此美妙的运行时环境,我们何不尝试自己编写一些符合心意的测试集,从而进一步测试自己的代码呢? 相信大家通过本期一生一芯计划的学习已经对于AM有所了解了,如果你对于AM的编译过程依然一知半解,可以参考AM 运行环境介绍在新窗口中打开

计时器中断

了解计时器中断

计时器中断属于内部中断,涉及到的mtime和mtimecmp属于外设,也就是SoC计算机系统的内容。 不过,我们为了便捷与例外处理的完整性,依然选择在这里介绍计时器中断。

Core Local Interrupt在新窗口中打开中介绍了CLINT的地址,我们可以根据该地址实现CLINT。 虽然CLINT属于外设,不过CLINT模块位于CPU内部,因此SoC并不提供,需要大家自行实现。 计时器中断和我们刚刚介绍的异常本质上均属于例外,因此处理流程并未有太大的区别。

计时器中断主要涉及到mipmiemtimemtimecmp这四个寄存器。 mip寄存器包含等待中断的信息; mie寄存器包含中断启用位; mtime寄存器是实时计数器,以恒定的频率增加,我们可以使其每周期自增1; mtimecmp寄存器是计时器比较寄存器。 当满足如下三个条件时,产生计时器中断,mip寄存器的MTIP位置1。

  1. mstatusMIE位为1
  2. mieMTIE位为1
  3. mtimemtimecmp

目前第四期一生一芯的SoC工程环境已经发布第四期一生一芯计划仿真用SoC工程在新窗口中打开,更多信息可以参考第三期一生一芯系列视频在新窗口中打开

选做编程题:测试计时器中断

为了对计时器中断进行测试,我们需要对AM中现有的测试程序进行一些修改,或者编写自己的测试程序。 在测试程序中,我们们可以通过MMIO的方式对mtimemtimecmp寄存器映射的地址进行赋值。

在这里给出两点提示:

  • 在测试前,需要打开计时器中断,包括mstatusMIE位和mieMTIE
  • 在每次触发计时器中断后,可以将mtimecmp增加一定数值,等待下次中断的到来

目前,在我们的NEMU中并不包括CLINT外设;同时由于NEMU并不是与NPC时钟精确的模拟器,即使加入CLINT外设也无法保证NEMU与NPC在同一时刻触发中断。 因此,如果我们接入NEMU作为DiffTest,在访问CLINT外设,或时钟中断发生时,我们需要跳过该条指令的对比,并将NPC的状态同步到NEMU中,以保证DiffTest的正确性。

最近更新时间:
贡献者: Zihao Yu, myyerrol