1. 课程导论与开发环境搭建

各位同学好,我是你们这门课的老张。在芯片设计这行摸爬滚打了十几年,从最初的 8051 到后来的 ARM,再到现在的 RISC-V,我算是亲眼见证了指令集架构的变迁。今天咱们开始第一讲,先把地基打牢。

说实话,RISC-V 的出现让我挺兴奋的。为什么?因为它真正做到了开放和简洁。你想想看,一个指令集架构,居然能像 Linux 一样开源,而且没有历史包袱,设计得干干净净。我个人习惯把 RISC-V 比作「芯片界的乐高」——基础模块就那么多,但你能搭出各种花样来。

1.1 RISC-V 指令集架构概览

RISC-V 的精髓在于「精简」。它不像 x86 那样背负着几十年的兼容性包袱,也不像 ARM 那样有复杂的授权体系。它的核心设计哲学就两条:模块化和可扩展。

核心要点:RISC-V 的基础指令集(RV32I)只有不到 50 条指令。这意味着什么?意味着你花一个下午就能把指令集手册翻完。我在项目中带新人时,通常要求他们三天内能手写汇编,一周内能看懂大部分指令编码。

咱们这门课用的是 RV32I 基础指令集,外加 M 扩展(乘除法)。五级流水线嘛,用基础指令集刚刚好。下面这张图展示了 RISC-V 指令集的模块化结构:

RISC-V 指令集模块化结构 RV32I 基础整数指令集(强制) 标准扩展(可选) M 扩展(乘除) F/D 扩展(浮点) A 扩展(原子) C 扩展(压缩) 用户自定义扩展(非标准,保留编码空间) 注:本课程使用 RV32I + M 扩展,覆盖五级流水线全部指令

指令格式方面,RISC-V 只有 6 种基本格式:R、I、S、B、U、J。每种格式的指令编码位置高度统一,比如所有指令的 rs1 和 rs2 都在固定位置。这个设计对硬件实现特别友好——你想想看,译码器不用到处找操作数位置了。

指令格式 用途 典型指令 特点
R 型 寄存器-寄存器运算 ADD, SUB, AND, OR 两个源寄存器 + 一个目的寄存器
I 型 立即数运算/加载 ADDI, LW, JALR 一个源寄存器 + 12 位立即数
S 型 存储指令 SW, SH, SB 两个源寄存器 + 12 位立即数(拆分)
B 型 条件分支 BEQ, BNE, BLT 两个源寄存器 + 12 位立即数(条件跳转)
U 型 高位立即数加载 LUI, AUIPC 20 位立即数 + 目的寄存器
J 型 无条件跳转 JAL 20 位立即数 + 目的寄存器

小技巧:刚开始学 RISC-V 指令编码时,别死记硬背。我一般让学生先记住 R 型和 I 型,其他格式都是在这两种基础上变出来的。比如 S 型其实就是 I 型的立即数拆成两段放,B 型是 S 型改了个立即数编码规则。

1.2 低功耗设计的意义

说到低功耗,我得先讲个真实案例。几年前我参与过一个物联网芯片项目,芯片本身功能都跑通了,性能也达标。结果一测功耗——待机电流 2mA!客户要求是 50μA。那段时间我几乎天天泡在实验室里,一根一根地查信号线,一个模块一个模块地关时钟。最后发现是一个不起眼的电平保持电路在漏电。

从那以后,我养成了一个习惯:设计一开始就把功耗预算算清楚。低功耗不是后期优化出来的,是设计出来的。

咱们这门课讲的是五级流水线,流水线本身就会引入额外的功耗——寄存器、旁路逻辑、控制逻辑都比单周期处理器多。但反过来想,流水线也能做功耗优化,比如时钟门控、操作数隔离、动态电压频率调整(DVFS)。

关键数据:在典型的 28nm 工艺下,一个五级流水线 RISC-V 处理器的动态功耗分布大致如下:

  • 取指阶段(IF):约 25% —— 主要是指令存储器访问
  • 译码阶段(ID):约 15% —— 译码逻辑和寄存器堆读取
  • 执行阶段(EX):约 30% —— ALU 和旁路逻辑
  • 访存阶段(MEM):约 20% —— 数据存储器访问
  • 写回阶段(WB):约 10% —— 寄存器堆写入

你可能会问:「为什么执行阶段功耗最高?」其实原因很简单——ALU 在做运算时,内部逻辑翻转最频繁,而且旁路逻辑要处理各种数据冒险,组合逻辑路径很长。我在项目中做过一次实验,把 ALU 的操作数隔离做好,执行阶段功耗直接降了 18%。

1.3 开发工具链安装与验证

工欲善其事,必先利其器。咱们这门课的核心工具链有三件套:Verilator(仿真器)、GTKWave(波形查看器)、以及 RISC-V 交叉编译工具链。下面我一步步带大家装好。

1.3.1 Verilator 安装

Verilator 是目前最快的 Verilog/SystemVerilog 仿真器之一。它把 HDL 代码编译成 C++ 代码,然后编译成可执行文件。跑起来比商业仿真器快不少,特别适合做处理器验证。

# Ubuntu/Debian 系统
sudo apt-get update
sudo apt-get install git perl python3 make autoconf g++ flex bison
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
sudo apt-get install libfl2 libfl-dev zlib1g zlib1g-dev

# 下载源码(我习惯用 4.228 版本,稳定)
git clone https://github.com/verilator/verilator
cd verilator
git checkout v4.228

# 编译安装
autoconf
./configure
make -j$(nproc)
sudo make install

# 验证安装
verilator --version

注意:我曾经遇到过一个问题——系统自带的 g++ 版本太老,编译 Verilator 时各种报错。建议 g++ 版本不低于 9.0。可以用 g++ --version 检查。如果版本太低,先升级 g++。

1.3.2 GTKWave 安装

GTKWave 是开源的波形查看器,支持 VCD、FST 等格式。界面虽然朴素,但功能一点不差。我个人习惯用它配合 Verilator 做调试。

# Ubuntu/Debian
sudo apt-get install gtkwave

# 验证安装
gtkwave --version

# 如果安装成功,会显示类似 "GTKWave 3.3.104" 的版本号

1.3.3 RISC-V 交叉编译工具链

咱们需要把 C 代码编译成 RISC-V 的机器码,然后加载到仿真模型里跑。这里我推荐用官方的 riscv-gnu-toolchain。

# 安装依赖
sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev
sudo apt-get install libmpfr-dev libgmp-dev gawk build-essential bison flex
sudo apt-get install texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev

# 克隆工具链(这个比较大,建议用 --depth=1 减少下载量)
git clone --depth=1 https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain

# 配置(只编译 RV32I,不带浮点)
./configure --prefix=/opt/riscv --with-arch=rv32im --with-abi=ilp32
make -j$(nproc)

# 添加环境变量
echo 'export PATH=$PATH:/opt/riscv/bin' >> ~/.bashrc
source ~/.bashrc

# 验证
riscv32-unknown-elf-gcc --version

省时技巧:编译工具链真的很慢,我第一次编译等了将近两个小时。建议用 make -j$(nproc) 并行编译。如果实在不想等,也可以直接下载预编译的二进制包,网上有很多。

1.3.4 验证环境

装完工具链后,咱们写个简单的测试程序验证一下。写一个 RISC-V 汇编程序,编译后用 Verilator 仿真,最后用 GTKWave 看波形。

// test.c
int main() {
    int a = 10;
    int b = 20;
    int c = a + b;
    return c;
}

// 编译成 RISC-V 机器码
riscv32-unknown-elf-gcc -march=rv32im -mabi=ilp32 -nostdlib -o test.elf test.c

// 反汇编检查
riscv32-unknown-elf-objdump -d test.elf

如果能看到类似 addi、add 这样的 RISC-V 指令,说明工具链工作正常。接下来咱们会在后续章节中,用 Verilator 跑一个完整的五级流水线仿真,并用 GTKWave 观察流水线各阶段的信号。

环境验证清单:

  1. verilator --version —— 显示版本号(如 4.228)
  2. gtkwave --version —— 显示版本号(如 3.3.104)
  3. riscv32-unknown-elf-gcc --version —— 显示 gcc 版本
  4. 编译一个简单的 C 程序,反汇编后能看到 RISC-V 指令