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全部正确

代码解析

📊 乘法器实现对比

实现周期数面积精度
移位加32极小精确
Booth编码4-8精确
华莱士树2-3精确
DSP单元1FPGA内置精确

FPGA通常使用内置DSP单元实现1周期32×32乘法。ASIC中,高性能处理器使用Booth+华莱士树的组合,3周期完成64位乘法。

🧪 实验练习

  1. 在当前实现基础上添加异常处理支持
  2. 实现流水线仿真,观察波形中的关键信号变化
  3. 添加性能计数器:统计吞吐量、延迟、利用率
  4. 前几课的模块集成,构建更完整的系统
M扩展指令仿真通过 — 8条乘除法指令完整实现
思考题:为什么RISC-V选择除零不产生异常?这对编译器优化有什么好处?
参考资料:RISC-V Spec §7 (M Extension) | Computer Organization and Design RISC-V Edition §3.5

📚 深入理解与实践建议

掌握本课内容需要结合理论学习和动手实践:

  1. 阅读源码:BOOM(Chisel)和Rocket(Chisel)是RISC-V处理器设计的最佳参考实现
  2. 修改实验:修改本课的Verilog代码,观察行为变化
  3. 波形仿真:使用GTKWave查看关键信号的时序关系
  4. 对比分析:将本课模块与前几课模块集成,测试端到端功能

开发环境

工具用途安装
Verilator 5.020Verilog编译仿真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

📖 推荐阅读

在线资源

🔧 开发工具链与实践环境

本课程推荐以下开发工具链:

工具用途安装命令
VerilatorVerilog编译/仿真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
SpikeISA模拟器从源码编译

快速验证

# 编译本课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受限 没有分支预测 → 流水线气泡严重

🔬 实验扩展:进阶挑战

完成基础实验后,尝试以下进阶挑战:

  1. 性能优化:使用流水线技术减少关键路径延迟
  2. 面积优化:资源共享、操作数合并、时钟门控
  3. 功耗优化:添加时钟门控、操作数隔离
  4. 形式验证:使用Yosys formal验证功能正确性
  5. FPGA综合:在Xilinx/Intel FPGA上实现并测量时序

调试技巧

💡 设计要点与常见陷阱

经验法则:如果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课,在整体课程中承上启下。每一课都构建在前一课的基础上,建议按顺序学习。

📚 推荐阅读

在线资源