跳转至

扩展开发指南

如果需要向示例 CPU 中添加其他的 RV 扩展支持,请参考本文档。在阅读本文档之前,请确定已经阅读过 实现细节

M/B-ext

  1. 首先,请实现一个对应的执行模块。请直接参考 exec/mem.sv 中访存模块的实现。执行单元中的模块可以阻塞流水线。
  2. stages/execute.sv 中添加对应的执行单元和分发逻辑。
  3. stages/instr_decode.svtypes/instr.sv 中添加对应的译码逻辑。

中断

和异常类似,但是请保证,只有在 Ex 不阻塞流水线的时候进行清空。

额外的,请注意:访存是不可逆副作用,如果 Ex 中正在执行访存请求,请等待这个访存请求进入 WB。

F/D/Q-ext

说真的,为什么要为难你自己。但是无论如何,我们推荐采用分离式 FPU 设计。

分离式 FPU

我们推荐直接使用 berkeley-hardfloat 实现运算,外加控制逻辑和 RegFile 。访存单元可以和主核共享。

在主核中对应的执行单元逻辑实现就可以和访存类似。

集成式 FPU

在 ID 中读取寄存器时需要判断数据来源。对于宽度宽于 XLEN 的浮点数(包括 berkeley-hardfloat 的重编码格式),需要注意扩展译码结果中寄存器值的宽度。

在写回时,也需要判断是在写谁。

U-ext

首先,请仔细阅读 RISC-V ISA Spec Volume 2, Privileged Spec。这里不会强调 ISA 的 Pitfall 。

S-ext / 内存地址映射

一部分 CSR (e.g. SIP) 在不同特权态下有不同的可读写性,或者读取的值和用于 CSRRC / CSRRS 的基础值可能存在不同。在示例 CPU 中没有考虑这种情况,需要额外添加支持。

RISC-V 由硬件查询页表,因此需要实现 TLB 和 PTW。如果你没有实现分离的 ICache 和 DCache,可以在访存仲裁器 components/mem_arbiter.sv 中实现 TLB 和 PTW。但是如果你实现了 Cache ,由于 Aliasing 的问题,注意要在 CPU <-> Cache 界面进行地址转换,并且 PTW 要接到 DCache 上。

C-ext

如果你希望运行 Rust 编译的软件,通常这会要求处理器支持压缩指令集 (C-ext)。

压缩指令集的主要问题在于取指的实现会复杂很多,并且有很多的 Corner case,尤其是和上述其他扩展结合的时候。以下是一些例子,希望能够成功劝退你。

  • 一个 4-Byte 指令一半处于一个 Page,另一半处于另一个 Page 的时候,发生了 Page fault。这个时候 stval 的值是什么?
  • 一个 JALR 跳到了奇数地址上,并且在未映射页面,这应该是什么异常?
  • JAL[R] 的返回地址是加几?

其余扩展

示例 CPU 的结构比较简单,对于其他扩展,例如分支预测、Cache、RV64、SMP (A-ext)、自定义指令集等,约束不大。在满足约定的情况下,可以随意实现。

更复杂的修改,例如乱序调度等,我们不推荐在示例 CPU 的基础上进行修改。


最后更新: 2020-11-03 03:02:10