1. RISC-V基础回顾:指令集架构概览、特权架构与模式、Hart概念与CSR寄存器

好,咱们正式开始。这一节算是整个课程的基石,说白了就是先把RISC-V的底子打牢。我见过不少工程师,上来就撸多核调度代码,结果连Hart和CSR都没搞明白,最后调试到怀疑人生。嗯,咱们不干那事。

1.1 指令集架构概览:为什么RISC-V能火?

RISC-V是个精简指令集,但它不是那种「为了精简而精简」的设计。我个人觉得,它最聪明的地方在于——模块化

你想想看,ARM的指令集是固定的,你要用就得全盘接受。RISC-V不一样,它把指令集拆成了两部分:

  • 基础指令集(Base ISA):比如RV32I、RV64I,这是必选项。加减乘除、访存、分支,都在这里。
  • 扩展指令集(Standard Extensions):比如M(乘除法)、F/D(单/双精度浮点)、A(原子操作)、C(压缩指令)。这些都是可选的,按需选配。

我在一个IoT项目里就只用RV32IMC,连浮点都不要,省面积省功耗。换做ARM?你得买一整套Cortex-M核,里面一堆你用不上的东西还得照单付费。

核心要点:RISC-V的指令集是「乐高式」的。基础块固定,扩展块自由组合。这给硬件设计者留了极大的发挥空间。

另外,RISC-V的指令编码非常规整。比如所有寄存器操作指令,源寄存器位置都是固定的(rs1在[19:15],rs2在[24:20])。这有什么好处?硬件解码器可以做得更简单、更快。我当年做乱序执行引擎时,就特别喜欢这种规整性——少了很多绕来绕去的解码逻辑。

1.2 特权架构与模式:你的CPU有几种「权限」?

好,指令集讲完了,咱们聊聊更关键的东西——特权架构

为什么需要特权架构?说白了,就是为了隔离。操作系统不能让你随便访问硬件寄存器,否则一个用户程序就能把整个系统搞崩。RISC-V定义了三种特权模式:

模式 编码 名称 典型用途
M 11 Machine Mode 最底层固件、安全监控、异常处理
S 01 Supervisor Mode 操作系统内核
U 00 User Mode 普通应用程序

注意,M模式是必须实现的。S和U是可选的。但如果你要做多核调度、跑Linux,那S模式是标配。

我曾经踩过一个坑:在设计一个双核RISC-V处理器时,我默认所有核都跑在M模式下,结果发现两个核都能直接操作中断控制器,互相抢资源,调度逻辑乱成一锅粥。后来老老实实引入S模式,让一个核跑S模式做调度,另一个核跑U模式做计算,问题迎刃而解。

避坑指南:多核系统中,务必明确每个Hart的特权模式。不要让所有核都跑在M模式下,否则中断和资源管理会变成噩梦。

模式之间通过异常(Exception)中断(Interrupt)来切换。比如用户程序执行了ecall指令,就会陷入S模式或M模式,由操作系统或固件来处理。这个机制,就是多核调度中「上下文切换」的基础。

1.3 Hart概念:别再说「核心」了,咱们说「硬件线程」

RISC-V里有个独特的概念——Hart(Hardware Thread)。

你可能会问:「这不就是CPU核心吗?」嗯,不完全一样。一个物理核心可以包含多个Hart。比如一个核心支持SMT(同步多线程),那它就有两个Hart。每个Hart都有自己的程序计数器(PC)、寄存器文件和CSR寄存器。

我习惯这么理解:Hart是调度的最小单位。操作系统看到的不是「核心」,而是「Hart」。每个Hart独立执行指令流,共享核心的执行单元(比如ALU、浮点单元)。

个人经验:在做多核调度策略时,我建议把Hart当作「虚拟CPU」来看待。调度器只需要关心有多少个Hart可用,而不必关心它们是否共享物理核心。这样设计更干净。

每个Hart都有一个唯一的Hart ID,存储在mhartid这个CSR寄存器中。多核启动时,每个Hart读取自己的mhartid,就知道自己该干什么。比如Hart 0负责初始化,Hart 1~N负责跑应用。

1.4 CSR寄存器:控制你的Hart

CSR(Control and Status Register)是RISC-V里控制Hart行为的「开关面板」。每个CSR都有12位的地址编码,通过csrrwcsrrscsrrc等指令来读写。

常用的CSR寄存器我列一下:

CSR地址 名称 作用
0x301 misa 机器模式ISA控制,标识支持的扩展
0x341 mepc 异常返回地址,保存触发异常的指令PC
0x342 mcause 异常原因,告诉你发生了什么异常
0x344 mie 机器模式中断使能,控制哪些中断可以触发
0x348 mip 机器模式中断挂起,显示哪些中断正在等待
0xF14 mhartid Hart ID,每个Hart唯一

举个例子,多核调度中,一个Hart要进入低功耗模式等待任务,可以这样操作:

# 关闭该Hart的中断使能
csrci mie, 0x1   # 清除mie中的全局中断使能位

# 执行WFI指令等待中断
wfi

# 被唤醒后,恢复中断使能
csrsi mie, 0x1

这段代码看起来简单,但我在实际项目中吃过亏——WFI指令在某些实现中可能不会立即返回。如果你用的是模拟器或FPGA原型,WFI的行为可能和真实芯片不一样。我建议在硬件验证阶段,多测几种WFI唤醒场景。

关键点:CSR寄存器是Hart的「私有财产」。每个Hart都有自己的CSR副本,互不干扰。这也是多核调度能独立控制每个Hart的基础。

1.5 小结:这一节你该记住什么?

好,咱们回顾一下。这一节我讲了四个东西:

  1. 指令集架构:模块化设计,基础指令集+扩展,按需选配。
  2. 特权模式:M/S/U三级,多核调度至少需要S模式。
  3. Hart概念:硬件线程,调度的最小单位,每个Hart有独立ID。
  4. CSR寄存器:控制Hart行为的开关,每个Hart私有。

这些东西看着基础,但后面讲多核调度策略时,你会反复用到它们。尤其是CSR和特权模式,几乎每个调度算法都绕不开。嗯,下一节咱们就进入正题——多核启动与同步。