Implement Exception Handling and RT-Thread

After implementing IOE, our next step is to implement CTE on both NEMU and NPC. Once implemented, we can run sophisticated operating systems!

Run RT-Thread on NEMU

Implement trap instructions in NEMU

Follow the PA lecture notes to complete Phase 1 of PA3 until you see the following prompt:

hint

Phase 1 of PA3 ends here.

Run RT-Thread on NEMU

Follow the PA lecture notes to complete Phase 1 of PA4 until RT-Thread is launched. The subsequent tasks related to Nanos-lite are not required to be completed for now.

Running RT-Thread on NPC

With the help of AM, we can run RT-Thread at a low cost. On the hardware side, we only need to implement a few CSRs, a few CSR instructions, ecall, mret instructions, and the corresponding exception handling mechanism.

  • In RISC-V, the address space for CSR registers is 12 bits, meaning there are 4096 possible registers. However, RISC-V defines only around 300 CSRs. Excluding performance counters and CSRs related to Physical Memory Protection (PMP), there are only about 78 CSRs. Further, if we consider only the CSRs needed in M mode, there are only about 28 CSRs. For running RT-Thread on NPC, we only need a handful, less than 5. Therefore, we do not need to instantiate all 4096 CSRs. Although this only occupies some memory for NEMU, it represents a significant area overhead for NPC. Practically, we only need to instantiate the CSRs that are needed, and then perform read and write operations based on their CSR addresses.
  • The CSRs we need to implement currently don't have any special side effects. Although the RISC-V manual describes many features of mstatus, we don't need to use them currently. We only need to initialize it correctly through DiffTest.
  • We only need to implement a few CSR instructions currently. Unlike typical instructions, CSR instructions atomically read/write to the same CSR register. Additionally, we can ignore the read/write attributes of each CSR field (if you haven't heard of this, you need to carefully read the manual), including WPRI, WLRL, and WARL. These attributes define the behavior when writing illegal values to CSR fields. Since the programs we currently run do not rely on these behaviors, we can temporarily skip implementing these read/write attributes.
  • ecall and mret both cause NPC to jump. We can easily implement this by reusing the data path of the address logic.
  • Currently, we only need to implement the ecall exception, which is an unconditional trap exception that NPC needs to respond to. We only need to set mcause and mepc simultaneously and then jump to the exception entry stored in mtvec.

Run RT-Thread on NPC

Implement a simple exception handling mechanism in NPC and run RT-Thread.

Fix the problem of not exporting the last command hint while RT-Thread is running

Careful you will see, unlike NEMU, when running RT-Thread, the last msh /> on the NPC is not exported. If you are interested in this issue, you can now think about how to solve this problem. You can also choose to ignore it, and you will encounter similar problems again when following up on SoC.

The complete exception handling mechanism in RISC-V is far more complex than what we are currently implementing. Commercial RISC-V processors must accurately implement every detail described in the manual, regardless of whether customers will use it. Implementing all CSRs and meticulously detailing every bit is actually an engineering-intensive task that requires a lot of effort from the engineering team. However, "OSOC" is ultimately an educational project. The goal is not to design a RISC-V processor that meets commercial delivery requirements. Therefore, we can simplify various complex mechanisms under the premise of correctly running demonstration programs, allowing everyone to focus on learning key principles and developing core functionality. As we run more programs in Stage A in the future, we will gradually add various CSRs and their core functionalities.

Last Updated:
Contributors: Zihao Yu