我们每天使用的电脑、手机、开发板和机器人,都离不开处理器。但你有没有想过:CPU 究竟是如何理解程序的?为什么同样一段 C 语言代码,换一台处理器就可能需要重新编译?为什么 Linux 既能运行在 x86 电脑上,也能运行在 ARM 和 RISC-V 处理器上?
这些问题的背后,都涉及一个重要概念:指令集架构(ISA,Instruction Set Architecture)。
RISC-V 就是一种开放标准的指令集架构。它的意义不仅在于提供了一套处理器指令,更在于让不同的企业、研究机构和开发者能够依据共同的标准设计自己的处理器。
这篇文章将从计算机的底层运行机制开始,逐步讲解 RISC-V 的架构、指令、寄存器、特权级、软件生态,并通过 Ubuntu 环境下的交叉编译实验,把理论与实践连接起来。
一、先建立整体认知:一台计算机究竟是怎样工作的?
在学习 RISC-V 之前,我们先看一张完整的计算机系统架构图。
正在绘制图表…
这张图展示的是概念层次,而不是严格的执行时间顺序。应用程序和操作系统都会使用指令集,处理器则通过具体的硬件实现来执行这些指令,可以把它理解成六个层次。
- 第一层:应用程序 例如我们编写的 C 语言程序、机器人运动控制程序或者图像识别程序。
- 第二层:编译器和链接器 它们将源代码转换成目标平台能够使用的机器代码,并处理函数调用、库依赖和符号地址等问题。
- 第三层:操作系统 Linux 负责管理进程、内存、文件、设备和权限,为应用程序提供运行环境。对于一些微控制器,也可以使用 RTOS,或者不运行操作系统,直接运行裸机程序。
- 第四层:指令集架构 ISA 它规定处理器能够识别哪些指令、寄存器如何使用,以及指令执行应当产生什么结果。
- 第五层:处理器微架构 它决定具体怎样实现这些指令,例如采用什么流水线、缓存结构、分支预测机制和执行单元。
- 第六层:数字电路与物理硬件 最终,处理器由晶体管构成的数字电路实现,并与内存、存储设备、总线和外设协同工作。
这里最重要的区别是:ISA 规定处理器应该做什么,微架构决定处理器具体怎么做。
例如,两款不同厂商的 CPU 可以实现相同的 RISC-V 指令集,但内部可能采用完全不同的流水线深度、缓存容量和执行策略。因此,它们能够运行相同架构的软件,却拥有不同的性能、功耗和成本。
- 理解这一点,才算真正进入计算机体系结构的世界
二、什么是指令集?CPU 为什么需要它?
我们先从一个最简单的程序开始。
int a = 10;
int b = 20;
int c = a + b;
对人而言,这段代码很容易理解:把 10 和 20 相加,再把结果保存到变量 c 中。但 CPU 并不直接理解 C 语言中的变量和加号。它需要执行经过编码的机器指令。在编译过程中,编译器会根据目标处理器的架构,将源代码转换为相应的机器指令。对于不同的处理器架构,生成的机器代码可能不同。
例如,某种机器指令可以表示整数加法,另一种可以表示从内存读取数据,还有一些指令负责条件判断、函数调用和程序跳转。这些指令的编码方式、操作数规则和执行语义,必须有统一的约定,否则软件就无法可靠地与处理器协作,这套约定,就是指令集架构。
2.1 ISA 到底规定了什么?
一个 ISA 通常需要定义以下内容:
- 指令集合: 处理器支持哪些运算、访存和控制流指令。
- 寄存器: 有哪些可供软件使用的寄存器,以及它们的基本用途。
- 数据类型和操作规则: 整数、浮点数等数据如何参与运算。
- 内存访问: 指令如何读取和写入内存,以及相关的访问规则。
- 异常与中断机制: 非正常情况或外部事件发生时,处理器如何响应。
- 特权机制: 软件如何在不同权限级别下执行,以及如何访问受保护的资源。
这些规则让软件开发者不必了解某款 CPU 内部的全部电路,也能够为它编写程序。
2.2 指令集、微架构、ABI 有什么区别?
这三个概念经常一起出现,但它们不是一回事。
| 概念 | 主要解决的问题 | 举例 |
|---|---|---|
| ISA 指令集架构 | 处理器支持什么指令、遵守什么行为规则 | RV64I、ARM AArch64、x86-64 |
| 微架构 | 如何在硬件中实现指令 | 流水线、乱序执行、缓存 |
| ABI 应用二进制接口 | 编译后的程序如何与其他程序、库和运行环境协作 | 函数参数传递、寄存器使用约定、数据布局 |
第一层:ISA 决定处理器能识别什么指令
如果目标架构是 RISC-V,编译器就会生成符合相应 RISC-V 指令集的代码。
例如,加法操作可能被编译为:
add a0, a0, a1
这里的 add 是 RISC-V 的整数加法指令,a0 和 a1 是寄存器的 ABI 名称,分别对应整数寄存器 x10 和 x11。
但需要注意:这条指令本身只描述寄存器之间的加法,并不规定 C 函数的参数一定要放在 a0 和 a1 中。
- ISA 规定指令的行为,ABI 才规定函数调用时如何使用寄存器。
第二层:微架构决定指令如何在硬件中执行
假设有两颗 CPU,它们都支持相同的 RISC-V 指令集。
一颗采用简单的顺序执行设计,另一颗采用更复杂的流水线和乱序执行设计。两者都可以正确执行同一条 add 指令,但内部实现方式、吞吐量、功耗和实际性能可能不同。
正在绘制图表…
这就是 ISA 与微架构的关系:它们可以不同,但只要实现符合规范,对软件可见的指令行为就应当保持一致。
第三层:ABI 决定程序之间如何配合
再回到 add() 函数,当另一个函数调用它时,调用方必须知道两个参数放在哪里,以及返回值从哪里读取。否则,即使 CPU 能够执行加法指令,程序也可能无法正确传递数据。
以常见的 RISC-V 64 位 Linux 调用约定为例,整数或指针参数通常通过 a0 至 a7 等寄存器传递,整数返回值通常通过 a0 返回,调用方和被调用方必须遵守同一套约定,才能正确协作。
ABI 还涉及其他规则,例如:
- 哪些寄存器由调用者保存,哪些由被调用函数保存。
- 栈如何使用,以及栈指针需要满足什么对齐要求。
- 数据类型的大小、布局与对齐方式。
- 可执行文件、动态库和系统调用如何与运行环境交互。
因此,ABI 不只是一个寄存器列表,而是一套让编译后的软件能够互相协作的二进制接口规则。此外,即使两边的指令集兼容,如果程序采用了不同的 ABI、依赖不同的系统库,或者目标操作系统不兼容,也可能无法直接运行。
可以把程序能否运行理解为多个条件共同决定的结果:
正在绘制图表…
这张图是简化的检查流程。实际兼容性还可能受到二进制文件格式、动态链接器、操作系统接口、硬件特性和程序依赖等因素影响。可以用一句话记住三者的区别:
ISA 规定处理器能执行什么,微架构决定处理器如何执行,ABI 规定编译后的程序如何与其他软件和运行环境协作。
三、RISC-V 是什么?为什么它与 ARM、x86 不一样?
RISC-V 是一种开放标准的指令集架构,诞生于加州大学伯克利分校的计算机架构研究项目。如今,RISC-V International 负责维护和推动相关标准的发展。
这里的 RISC 是 Reduced Instruction Set Computer,即精简指令集计算机;V 则是罗马数字中的 5。RISC-V 的重要特点不是简单地让指令变少,而是采用相对精简的基础整数指令集,并通过标准化扩展增加不同领域需要的功能。
它最值得关注的地方有两个:
一是开放标准。 开发者可以依据公开的指令集规范设计处理器,而不必先取得传统商业指令集的使用授权。
二是模块化设计。 处理器可以选择符合自身需求的基础指令集与标准扩展,不同实现不必拥有完全相同的功能。
官方规范对 RISC-V 的定义正是以基础整数指令集为核心,再叠加可选扩展。
https://docs.riscv.org/reference/isa/v20250508/unpriv/intro.html
3.1 RISC-V、ARM、x86 的核心区别
| 维度 | RISC-V | ARM | x86 |
|---|---|---|---|
| 指令集模式 | 开放标准 | 商业授权体系 | 商业授权体系 |
| 指令集设计 | 基础指令集与可选扩展 | 具有多种架构与扩展 | 具有成熟的复杂指令集传统 |
| 处理器实现 | 可以自行实现或采用开放实现 | 可采用授权设计或自研实现等模式 | 主要由拥有相关权利的厂商实现 |
| 典型生态 | 嵌入式、研究、部分通用计算等 | 手机、嵌入式、服务器等 | 桌面电脑、工作站、服务器等 |
| 主要优势 | 开放、灵活、可定制 | 成熟生态、丰富的商业实现 | 强大的既有软件兼容性和产业基础 |
需要强调:RISC-V 开放的是指令集标准,并不意味着所有 RISC-V 芯片都免费,也不要求每个处理器项目必须开源所有硬件设计。
芯片企业仍然需要投入架构设计、验证、制造、封装、测试和软件适配等成本。
同时,ARM 与 x86 的商业授权方式并不完全相同,不能简单地认为所有相关产品都采用同一种授权模式。
3.2 为什么开放指令集很重要?
可以把 ISA 想象成一种语言标准。
如果不同的企业都能查阅并遵循相同的语言规范,它们就可以分别制造能够相互理解的设备。
RISC-V 也是如此:指令集标准定义了软件与处理器之间的共同规则。企业可以在遵循标准的基础上,设计不同的处理器产品。
但要注意,开放标准并不会自动保证软件兼容性。处理器是否支持某个扩展、系统是否实现相应的 ABI、驱动程序是否齐全,都会影响实际使用。
因此,RISC-V 的意义不是“所有芯片都变成一样”,而是让不同的实现能够建立在一套开放、可共同发展的标准之上。
四、RISC-V 指令集架构详解:RV32I、RV64I 和扩展
这是理解 RISC-V 最重要的一节。
很多人第一次看到 RISC-V,会遇到 RV32I、RV64I、RV64GC 这样的名称。如果不知道这些字符的含义,就很难判断某个处理器究竟支持什么。
4.1 RV32I 与 RV64I
我们先看名称的含义。
RV:RISC-V。32或64:基础整数寄存器的宽度,即 XLEN。I:基础整数指令集。
因此:
RV32I:32 位基础整数指令集。RV64I:64 位基础整数指令集。
这里的 32 位和 64 位不是指 CPU 的性能等级,也不代表它的时钟频率。
它们主要影响整数寄存器宽度、整数运算语义,以及架构所支持的地址与数据处理能力。实际可用的物理内存还受到处理器实现、内存控制器和平台设计等因素限制。
4.2 为什么 RISC-V 采用基础指令集 + 扩展?
假设设计一颗只负责简单控制任务的微控制器。
它可能只需要整数运算、分支跳转和内存访问,不一定需要复杂的浮点运算能力。
而另一颗用于运行 Linux 的处理器,可能需要乘除法、原子操作、浮点运算以及特权架构支持。
如果强制所有处理器都具备完全相同的功能,某些应用就可能承担不必要的实现成本。
RISC-V 通过扩展机制,让设计者根据实际需求组合不同的功能。
正在绘制图表…
图中列出的是典型示例,并不是完整的扩展清单。各扩展还可能具有依赖关系和不同的规范版本。
4.3 常见扩展的含义
| 扩展 | 主要功能 | 为什么重要 |
|---|---|---|
M | 整数乘法与除法 | 支持常见算术运算 |
A | 原子内存操作 | 支持多核同步等场景 |
F | 单精度浮点运算 | 处理单精度浮点数 |
D | 双精度浮点运算 | 处理双精度浮点数 |
C | 压缩指令 | 减少部分指令的编码长度 |
V | 向量运算 | 对多个数据元素执行并行操作 |
B | 位操作扩展族 | 提供更多位运算能力 |
例如,向量扩展可以帮助处理器更高效地处理某些具有数据并行特征的任务。但它并不意味着采用向量扩展的 CPU 就一定能替代 GPU,也不能单凭扩展名称推断实际性能。
实际性能还取决于微架构、执行宽度、内存带宽、编译器和具体工作负载。
4.4 如何读懂 RV64GC?
RV64GC 是一个常见的架构名称。
RV64:64 位基础整数架构。G:一个传统的简写,表示常用的I、M、A、F、D等基础功能组合,并包含相应的标准系统支持扩展。C:压缩指令扩展。
这里的 G 不是指图形处理器,也不是指通用 GPU。
另外,随着标准发展,某些扩展可以单独写出名称,工具链也可以通过更完整的 ISA 字符串表达处理器支持的功能。遇到具体产品时,最好查看其架构配置和工具链文档,而不是只凭一个简写猜测所有能力。
官方扩展命名规则可参考:https://docs.riscv.org/reference/isa/unpriv/naming.html
五、RISC-V 的寄存器与指令:CPU 实际在执行什么?
如果想真正理解 RISC-V,而不仅仅是认识它的概念,就需要了解寄存器和汇编指令。
5.1 什么是寄存器?
寄存器是处理器内部用于保存数据、地址或控制信息的存储单元。与访问主内存相比,处理器通常可以更直接地使用寄存器中的数据。
以 RISC-V 的基础整数寄存器为例,通用寄存器通常使用 x0 到 x31 进行编号。
其中:
| 寄存器 | 常见 ABI 名称 | 主要用途 |
|---|---|---|
x0 | zero | 恒为 0,写入结果会被丢弃 |
x1 | ra | 返回地址 |
x2 | sp | 栈指针 |
x5–x7 | t0–t2 | 临时寄存器 |
x8 | s0/fp | 保存寄存器,也可作为帧指针 |
x10–x11 | a0–a1 | 参数传递,也常用于返回值 |
x12–x17 | a2–a7 | 参数传递等 |
x18–x27 | s2–s11 | 保存寄存器 |
x28–x31 | t3–t6 | 临时寄存器 |
这是常见的 ABI 寄存器用途概览。完整的调用约定还规定了哪些寄存器由调用者保存、哪些由被调用函数保存,以及栈的使用规则。
要特别记住:x0 是一个特殊寄存器,它始终读取为零。
例如,一条指令把计算结果写入 x0,并不会真正保存这个结果。这一特性在编写低层代码时很有用。
5.2 用汇编理解一次加法
假设我们希望计算:
对应的 RISC-V 汇编可以写成:
li a0, 10
li a1, 20
add a0, a0, a1
ret
逐行解释:
li a0, 10:将数值 10 加载到a0。li a1, 20:将数值 20 加载到a1。add a0, a0, a1:将a0和a1的值相加,把结果写回a0。ret:返回调用者。
这里需要注意,li 和 ret 是汇编器提供的伪指令,汇编器会根据具体情况将它们转换为真正的机器指令;add 则是实际的 RISC-V 指令。这段代码揭示了一个重要事实:高级语言中的一次简单运算,最终可以拆解为处理器能够执行的低层操作。
5.3 RISC-V 指令有哪些基本类型?
RISC-V 的基础指令采用不同的编码格式。常见的基础编码格式包括 R、I、S、B、U 和 J 型。
| 类型 | 常见用途 | 示例 |
|---|---|---|
| R 型 | 寄存器之间的算术与逻辑运算 | add、sub |
| I 型 | 立即数运算、部分加载与间接跳转 | addi、lw、jalr |
| S 型 | 存储数据到内存 | sw |
| B 型 | 条件分支 | beq、bne |
| U 型 | 构造较大的立即数 | lui、auipc |
| J 型 | 跳转与链接 | jal |
这些名称不仅是分类,更与机器指令的二进制编码结构相关。
以 R 型指令为例,它通常包含操作码、源寄存器编号、目的寄存器编号,以及用于区分具体操作的功能字段。
31 25 24 20 19 15 14 12 11 7 6 0
+----------+-------+-------+------+-------+---------+
| funct7 | rs2 | rs1 |funct3| rd | opcode |
+----------+-------+-------+------+-------+---------+
这是标准 32 位 R 型指令的字段布局示意。
其中:
opcode:指示指令所属的主要类别。rd:目的寄存器。rs1、rs2:源寄存器。funct3、funct7:进一步区分具体操作。
例如,add 和 sub 都使用 R 型编码,但它们的功能字段不同。
需要注意的是,并非所有 RISC-V 指令都是 32 位长。压缩指令扩展 C 引入了 16 位指令编码,因此不能认为每一条 RISC-V 指令都固定占用 4 个字节。
5.4 CPU 如何执行一条指令?
在学习计算机组成原理时,经常会遇到“取指、译码、执行”这几个概念。
可以把一个简单的处理过程理解为:
正在绘制图表…
PC 是程序计数器,用于跟踪程序执行位置。实际执行过程中,分支、跳转、异常和中断都可能改变后续执行位置;某些指令还会直接读写内存,因此并非每条指令都具有相同的写回流程。
现代 CPU 还可能使用流水线、乱序执行和推测执行等技术来提升性能。这些属于微架构实现细节,并不是 RISC-V ISA 必须采用的唯一执行方式。
这也再次说明:指令集规范定义指令的行为,而处理器可以采用不同的内部设计来完成这些行为。
六、特权级:为什么 CPU 不允许所有程序随意访问硬件?
前面介绍了普通的整数运算和寄存器,但现代操作系统还需要处理一个更重要的问题:权限。
如果每个应用程序都能随意修改内存管理配置、控制硬件或者关闭关键中断,那么系统就很难保证稳定性和安全性。
因此,RISC-V 的特权架构定义了不同的执行权限。
常见的特权级包括:
- M 模式(Machine): 机器模式,拥有最高的架构特权。
- S 模式(Supervisor): 监管者模式,通常用于操作系统内核。
- U 模式(User): 用户模式,通常用于普通应用程序。
具体实现可以支持不同的模式组合。例如,一些简单的微控制器可能只实现 M 模式,而能够运行 Linux 的应用处理器通常需要支持 S 模式及相应的内存管理能力。
6.1 Linux 为什么需要 S 模式?
在典型的 Linux 系统中,普通应用程序运行在 U 模式,内核主要运行在 S 模式,而启动固件或底层监控程序可能在 M 模式中执行。
当应用程序需要操作文件、申请内存或者与设备交互时,它不能直接绕过操作系统随意修改所有硬件状态,而是通过系统调用等受控机制请求内核服务。
正在绘制图表…
这张图是典型平台的概念示意。实际系统中,M 模式固件与 S 模式内核之间的关系取决于启动方式、固件接口和平台实现。
6.2 机器模式与启动固件
当处理器上电或复位时,它不会直接进入一个已经运行着完整 Linux 的状态。
系统需要先执行底层启动代码,完成必要的硬件初始化,再逐步加载操作系统。
在 RISC-V 平台上,机器模式通常承担部分底层初始化与特权管理职责。某些系统会使用 OpenSBI 等固件,为更高特权级的软件提供标准化的底层服务。
这里需要区分三个概念:
- ISA 规定处理器的指令和特权行为。
- 固件负责平台初始化及特定底层服务。
- Linux 内核负责更高层的操作系统功能。
它们协同工作,才形成可以启动和运行应用程序的完整系统。
七、从上电到运行 Linux:RISC-V 系统启动框架
如果想理解 RISC-V 与 Linux 的关系,就不能只停留在“它们可以兼容”这句话上,还需要了解系统启动的基本过程。
典型的 Linux 设备启动流程可以概括为:
正在绘制图表…
这是一种常见的启动模型,并非所有 RISC-V 设备都必须经过完全相同的步骤。有些微控制器直接执行裸机程序,有些平台使用不同的引导固件,也有些平台由固件直接加载内核。
对于运行 Linux 的系统,启动过程通常涉及处理器初始化、内存准备、设备树或 ACPI 等平台信息、内核启动以及根文件系统挂载等环节。
Linux 内核的 RISC-V 官方文档提供了启动要求、启动镜像、虚拟内存布局等具体说明:https://www.kernel.org/doc/html/latest/arch/riscv/index.html
7.1 为什么 x86 程序不能直接在 RISC-V 上运行?
假设你在 x86-64 Ubuntu 上编译了一个可执行文件。
这个文件内部包含针对 x86-64 的机器指令。即使它调用的是相同的 Linux API,RISC-V CPU 也不能直接把这些指令当作自己的原生指令执行。
通常需要针对 RISC-V 重新编译程序,并确保目标架构、ABI、依赖库和系统环境匹配。
另一种方式是使用模拟器或二进制翻译工具,让目标程序在不同的指令集环境中运行,但这涉及额外的兼容层。
因此:
Linux 是可以跨架构移植的操作系统内核,但普通的原生可执行文件通常不能在不同 ISA 之间直接通用。
八、RISC-V 在机器人与 AI 硬件中的意义
理解了指令集、处理器和操作系统,我们就可以把这些知识联系到实际的机器人系统。
一台机器人往往并不是由一颗 CPU 完成所有任务,而是由多种计算单元和控制器共同组成。
例如:
正在绘制图表…
这只是常见的逻辑划分示意,真实系统也可能把部分传感器处理、运动控制和通信功能集成在同一颗芯片中。
不同层级的计算任务有不同的需求:
- 主计算平台需要处理感知、规划和复杂应用。
- 实时控制器需要保证任务在规定时间内响应。
- 电机驱动器可能集成专用控制逻辑和功率电子电路。
- AI 加速器可以负责特定的并行计算任务。
RISC-V 可以作为其中某些处理器或控制器的指令集选择,但并不是所有机器人都需要采用 RISC-V。
实际工程中,还必须考虑实时性能、外设接口、驱动支持、工具链、功耗、成本和长期维护等因素。
这也说明,学习 RISC-V 并不是为了记住一个芯片品牌,而是为了理解底层计算平台如何支撑上层机器人系统。
九、Ubuntu 实战:快速编译一个 RISC-V 程序
前面的内容主要是理论,下面我们在 Ubuntu 上做一个简单实验,亲自观察程序如何被编译成 RISC-V 目标代码。
需要说明:在 x86 Ubuntu 上交叉编译 RISC-V 程序,不代表你的电脑已经变成了 RISC-V 处理器。 交叉编译器只是让你为另一种架构生成程序。
9.1 安装工具链
在 Ubuntu 上,可以先尝试安装常见的 RISC-V Linux 交叉编译工具链和用户态模拟器:
sudo apt update
sudo apt install gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu qemu-user
不同 Ubuntu 版本、软件源和处理器架构下,软件包的可用性可能有所不同。如果安装失败,需要根据当前发行版的软件包仓库调整。
安装后检查编译器:
riscv64-linux-gnu-gcc --version
如果能够显示版本信息,说明编译器已经可以使用。
9.2 编写一个 C 程序
新建文件:
nano hello.c
输入:
#include <stdio.h>
int main(void)
{
int a = 10;
int b = 20;
int c = a + b;
printf("Hello RISC-V!\n");
printf("Result = %d\n", c);
return 0;
}
保存文件后,我们就可以尝试将它编译成面向 RISC-V Linux 的程序。
9.3 交叉编译
执行:
riscv64-linux-gnu-gcc \
-march=rv64gc \
-mabi=lp64d \
-O2 \
hello.c \
-o hello-riscv
这里有几个值得理解的参数:
| 参数 | 含义 |
|---|---|
-march=rv64gc | 指定目标 ISA,包括 RV64 基础架构和相应扩展 |
-mabi=lp64d | 指定 64 位整数、64 位指针及双精度浮点相关的 ABI 约定 |
-O2 | 启用常见的编译优化 |
-o hello-riscv | 指定输出文件名 |
需要注意,rv64gc 和 lp64d 是一组常见的目标配置,并不适合所有 RISC-V 处理器。如果目标硬件缺少相应扩展,或使用不同 ABI,编译参数就需要调整。
9.4 查看生成的文件
执行:
file hello-riscv
如果编译成功,输出通常会显示这是一个面向 RISC-V 64 位架构的 ELF 可执行文件。
ELF 是 Executable and Linkable Format,即可执行与可链接文件格式。它规定了程序的代码、数据、符号和其他信息如何组织。
再查看 ELF 头:
riscv64-linux-gnu-readelf -h hello-riscv
重点观察 Machine 等字段。对于 RISC-V ELF 文件,相关字段会标识其目标机器架构。
这一步非常重要:我们不只是生成了一个文件,而是可以通过文件格式信息验证它的目标架构。
9.5 查看汇编代码
执行:
riscv64-linux-gnu-gcc \
-march=rv64gc \
-mabi=lp64d \
-O2 \
-S hello.c \
-o hello.s
然后查看:
less hello.s
你会看到编译器生成的 RISC-V 汇编代码。
由于启用了 -O2 优化,编译器可能提前计算 10 + 20,而不是保留原本的两个变量和加法指令。因此,最终汇编不一定和源代码逐行对应。
这恰好说明,编译器不仅负责翻译语法,还会进行常量折叠、寄存器分配和其他优化。
9.6 尝试运行程序
如果系统安装了支持 RISC-V Linux 用户态程序的 QEMU,并且目标程序使用的动态库与运行环境兼容,可以尝试:
qemu-riscv64 \
-L /usr/riscv64-linux-gnu \
./hello-riscv
预期输出:
Hello RISC-V!
Result = 30
如果出现动态加载器或共享库错误,通常需要检查目标架构的运行库是否安装、-L 指定的根目录是否正确,以及程序的动态解释器路径是否与当前环境匹配。
这个实验的完整链路是:
正在绘制图表…
在这个过程中,源代码由 x86 主机上的编译器处理,生成 RISC-V 机器代码,再由模拟器提供目标指令集的执行环境。
QEMU 用户态模拟并不等于完整模拟一台 RISC-V 计算机。它主要帮助执行目标架构的用户态程序,并依赖宿主系统提供相应的系统调用支持。
十、最后的思考:RISC-V 真正改变的是什么?
学习 RISC-V 之后,我觉得最值得关注的,不是它是否能够取代 ARM 或 x86,而是它为处理器产业提供了另一种参与方式。
过去,设计处理器不仅需要工程能力,还要考虑指令集授权、软件兼容性以及整个生态的支持。开放指令集为更多研究者和企业提供了依据共同标准进行设计的机会。
但开放并不等于没有门槛。设计一颗高性能 CPU,依然需要大量的架构设计、验证、制造和软件工程投入。一个成熟的处理器平台,也不仅仅由指令集构成,还需要编译器、操作系统、驱动程序、开发工具和稳定的供应链。
因此,我更倾向于把 RISC-V 看作一种值得长期关注的计算基础设施,而不是一个必然战胜其他架构的技术概念。
对于机器人和 AI 硬件而言,真正重要的问题是:我们能否根据实际任务,合理组合处理器、加速器、控制器和软件系统,在性能、功耗、成本和可靠性之间找到更好的平衡?
RISC-V 为这种探索提供了一个开放的选择,但能否创造实际价值,最终仍取决于工程实现与产业生态。
官方资料
- RISC-V 官方规范库:基础指令集、标准扩展、特权架构及相关规范。
- RISC-V 指令集概览:理解基础整数指令集与可选扩展。
- RISC-V 扩展命名规则:学习 RV32I、RV64I 及扩展名称。
- Linux 内核 RISC-V 架构文档:学习 Linux 的 RISC-V 启动、ABI 与平台支持。
- QEMU 官方文档:进一步学习模拟器与不同目标架构的运行环境。