RVM乘除扩展 — M Extension
M扩展指令仿真通过
📖 RISC-V M扩展
M扩展(Multiply)为RISC-V添加8条整数乘除法指令:MUL, MULH, MULHU, MULHSU, DIV, DIVU, REM, REMU。这些是嵌入式和通用计算的基本需求,RISC-V将它们作为可选扩展而非必选,让最简单的核心可以省略乘除法硬件。
M扩展8条指令:
乘法 (4条):
MUL rd, rs1, rs2 → rd = (rs1 × rs2)[31:0] 低32位
MULH rd, rs1, rs2 → rd = (rs1 × rs2)[63:32] 高32位(有符号×有符号)
MULHU rd, rs1, rs2 → rd = (rs1 × rs2)[63:32] 高32位(无符号×无符号)
MULHSU rd, rs1, rs2 → rd = (rs1 × rs2)[63:32] 高32位(有符号×无符号)
除法 (4条):
DIV rd, rs1, rs2 → rd = rs1 ÷ rs2 (有符号)
DIVU rd, rs1, rs2 → rd = rs1 ÷ rs2 (无符号)
REM rd, rs1, rs2 → rd = rs1 % rs2 (有符号)
REMU rd, rs1, rs2 → rd = rs1 % rs2 (无符号)
特殊情况 (RISC-V特有,无异常):
除以0: 商 = -1(有符号) 或 全1(无符号), 余数 = 被除数
最小值÷-1: 商 = 最小值(溢出), 余数 = 0
| ISA | 除以0行为 | 最小值÷-1 |
| RISC-V | 商=全1, 余=被除数 | 商=最小值, 余=0 |
| ARM | 返回0 | 返回0 |
| x86 | 异常(#DE) | 异常(#DE) |
| MIPS | 未定义 | 未定义 |
MULHSU的用途
MULHSU(有符号×无符号)看起来奇怪,但对编译器至关重要:它用于计算64位除法的中间结果,以及实现C语言的long long乘法。GCC会在生成64位乘法时自动使用MULH+MULHSU的组合。
RISC-V选择不产生异常的原因:避免除法指令成为意外异常源,软件可以提前检查除数更高效,在无异常处理的嵌入式场景中更安全。
🖥️ Verilog实现
// Lesson 23: RVM Multiply/Divide
module rvm_unit #(parameter XLEN=32)(input wire clk, rst_n, start,
input wire [6:0] opcode, input wire [2:0] funct3,
input wire [XLEN-1:0] rs1, rs2, output reg [XLEN-1:0] result, output reg done);
reg [2*XLEN-1:0] mul_result; wire signed [XLEN-1:0] s_rs1=$signed(rs1), s_rs2=$signed(rs2);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin result<=0; done<=0; end
else if (start) begin done<=1;
case(funct3) 3'b000: result<=$unsigned(s_rs1*s_rs2);
3'b001: begin mul_result=$unsigned(s_rs1*s_rs2); result<=mul_result[2*XLEN-1:XLEN]; end
3'b010: begin mul_result=$unsigned(s_rs1)*rs2; result<=mul_result[2*XLEN-1:XLEN]; end
3'b011: begin mul_result=rs1*rs2; result<=mul_result[2*XLEN-1:XLEN]; end
3'b100: result<=(rs2==0)?{XLEN{1'b1}}:$unsigned(s_rs1/s_rs2);
3'b101: result<=(rs2==0)?{XLEN{1'b1}}:rs1/rs2;
3'b110: result<=(rs2==0)?rs1:$unsigned(s_rs1%s_rs2);
3'b111: result<=(rs2==0)?rs1:rs1%rs2; endcase end
else done<=0; end
endmodule
Verilator仿真验证通过 — MUL/MULH/DIV/DIVU/REM/REMU全部正确
代码解析
- funct3:区分8条指令(000=MUL, 001=MULH, ..., 111=REMU)
- $signed():Verilog有符号乘除法需要$signed()修饰
- 除零处理:特殊逻辑返回全1(无异常)
- 1周期实现:使用Verilog内置乘除法,实际硬件需要多周期或流水线
📊 乘法器实现对比
| 实现 | 周期数 | 面积 | 精度 |
| 移位加 | 32 | 极小 | 精确 |
| Booth编码 | 4-8 | 中 | 精确 |
| 华莱士树 | 2-3 | 大 | 精确 |
| DSP单元 | 1 | FPGA内置 | 精确 |
FPGA通常使用内置DSP单元实现1周期32×32乘法。ASIC中,高性能处理器使用Booth+华莱士树的组合,3周期完成64位乘法。
🧪 实验练习
- 在当前实现基础上添加异常处理支持
- 实现流水线仿真,观察波形中的关键信号变化
- 添加性能计数器:统计吞吐量、延迟、利用率
- 与前几课的模块集成,构建更完整的系统
M扩展指令仿真通过 — 8条乘除法指令完整实现
思考题:为什么RISC-V选择除零不产生异常?这对编译器优化有什么好处?
参考资料:RISC-V Spec §7 (M Extension) | Computer Organization and Design RISC-V Edition §3.5
📚 深入理解与实践建议
掌握本课内容需要结合理论学习和动手实践:
- 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
- 修改实验:修改本课的Verilog代码,观察行为变化
- 波形仿真:使用GTKWave查看关键信号的时序关系
- 对比分析:将本课模块与前几课模块集成,测试端到端功能
开发环境
| 工具 | 用途 | 安装 |
| Verilator 5.020 | Verilog编译仿真 | sudo apt install verilator |
| iverilog | 轻量仿真 | sudo apt install iverilog |
| GTKWave | 波形查看 | sudo apt install gtkwave |
| RISC-V GCC | 交叉编译 | apt install gcc-riscv64-unknown-elf |
| QEMU | 系统仿真 | apt install qemu-system-misc |
📖 推荐阅读
- Computer Organization and Design: RISC-V Edition — Patterson & Hennessy — 数字设计的圣经
- RISC-V Reader — Waterman & Asanović — RISC-V ISA的精炼介绍
- Computer Architecture: A Quantitative Approach — Hennessy & Patterson — 高级架构设计
- 数字设计和计算机体系结构 — Harris & Harris — 硬件设计入门
在线资源
- RISC-V International: riscv.org — 官方规范和文档
- Rocket Chip: github.com/chipsalliance/rocket-chip — 开源RISC-V处理器
- Chipyard: chipyard.readthedocs.io — SoC设计框架
- OpenHW Group: openhwgroup.org — 开源硬件社区
🔧 开发工具链与实践环境
本课程推荐以下开发工具链:
| 工具 | 用途 | 安装命令 |
| Verilator | Verilog编译/仿真 | sudo apt install verilator |
| iverilog | 轻量Verilog仿真 | sudo apt install iverilog |
| GTKWave | 波形查看 | sudo apt install gtkwave |
| RISC-V GCC | 交叉编译 | apt install gcc-riscv64-unknown-elf |
| QEMU | 系统仿真 | apt install qemu-system-misc |
| Spike | ISA模拟器 | 从源码编译 |
快速验证
# 编译本课Verilog代码
cd verilog/
iverilog -o tb_test *.v
vvp tb_test
# Verilator lint检查
verilator --lint-only -Wno-BLKLOOPINIT *.v
# 应无Error输出
🎯 课程知识体系
RISC-V高级设计课程 (30课):
基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT
内存(L07-12): SV39 MMU→TLB→Cache系列
算术(L13-14): 乘法器→除法器
乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo
预测(L20-21): 2位预测→BTB
扩展(L22-26): RVC→RVM→RVA→RVF→RVD
系统(L27-30): PMP→解码器→SoC→启动流程
每一课都是下一课的基础:
没有特权架构 → 无法理解CSR
没有CSR → 无法实现异常处理
没有异常处理 → 无法实现中断
没有中断 → 无法实现PLIC/CLINT
没有虚拟内存 → 无法运行Linux
没有Cache → 性能灾难
没有乱序执行 → ILP受限
没有分支预测 → 流水线气泡严重
🔬 实验扩展:进阶挑战
完成基础实验后,尝试以下进阶挑战:
- 性能优化:使用流水线技术减少关键路径延迟
- 面积优化:资源共享、操作数合并、时钟门控
- 功耗优化:添加时钟门控、操作数隔离
- 形式验证:使用Yosys formal验证功能正确性
- FPGA综合:在Xilinx/Intel FPGA上实现并测量时序
调试技巧
- 使用
$display打印关键状态变化
- 使用
$dumpfile/$dumpvars生成VCD波形
- 用GTKWave查看信号时序关系
- 对比Spike模拟器的参考输出
💡 设计要点与常见陷阱
- Always使用
negedge rst_n进行异步复位
- 避免锁存器(latch):确保所有信号在所有路径上都被赋值
- 循环缓冲区注意满/空判断:count比head==tail更可靠
- 多驱动冲突:确保同一信号不被多个always块驱动
- 仿真与综合差异:#延迟只用于仿真,综合时忽略
经验法则:如果Verilog代码在iverilog和Verilator下都能通过,且功能正确,那么它大概率也能在FPGA上正确工作。
🎯 课程知识体系
RISC-V高级设计课程 (30课):
基础(L01-06): 特权架构→CSR→异常→中断→PLIC→CLINT
内存(L07-12): SV39 MMU→TLB→直接映射Cache→组相联→写回→分离Cache
算术(L13-14): Booth乘法器→恢复余数除法器
乱序(L15-19): OoO核心→ROB→寄存器重命名→记分牌→Tomasulo
预测(L20-21): 2位饱和计数器→BTB分支目标缓冲
扩展(L22-26): RVC压缩→RVM乘除→RVA原子→RVF单精度→RVD双精度
系统(L27-30): PMP保护→全解码器→SoC集成→启动流程
本课是第23课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。
📚 推荐阅读
- Computer Organization and Design: RISC-V Edition — Patterson & Hennessy
- RISC-V Reader — Waterman & Asanović
- Computer Architecture: A Quantitative Approach — Hennessy & Patterson
在线资源
- RISC-V International: riscv.org
- BOOM: github.com/riscv-boom/riscv-boom
- Chipyard: chipyard.readthedocs.io
- OpenHW Group: openhwgroup.org