Lesson 17

√ 开方器

🏆 牛顿迭代法开方正确
✅ Verilator仿真验证通过

📖 实验描述

实现16位整数开方器,使用逐位试探法从MSB到LSB逐位确定结果。

开方运算在信号处理、图形学和科学计算中广泛使用。硬件实现常用两种方法: 1. 逐位试探法(本实验采用):从最高位开始,逐位试探是否可以置1,检查 trial_root^2 <= radicand。 2. Newton-Raphson迭代法:x[n+1] = (x[n] + N/x[n])/2,收敛快但需要除法器。 逐位试探法的优势:无需除法器,每步只需比较和乘法,8步即可完成8位开方,适合硬件实现。 结果为整数平方根(向下取整):sqrt(99)=9, sqrt(100)=10。

🧠 核心概念

📐 电路结构

电路与状态图
逐位试探开方器:

  radicand[15:0] → 比较器 ←── trial^2
                        │
                  trial^2 <= radicand?
                   ↓是          ↓否
              root[i]=1    root[i]=0

  trial_root = root | (1 << bit_pos)
  每周期试探1位,8周期完成

📝 设计步骤

  1. 1初始化:root=0, bit_pos=7
  2. 2构造试探值:trial=root | (1<
  3. 3计算试探平方:trial_sq=trial*trial
  4. 4比较:若radicand>=trial_sq则root←trial
  5. 5bit_pos--,重复直到bit_pos=0
  6. 6输出:sqrt_out=root

💻 Verilog实现

sqrt_newton.svSystemVerilog · Verilator 5.020
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
// Square Root - 逐位试探法
// 从MSB到LSB逐位试探,检查 root^2 <= radicand
module sqrt_newton(
    input  wire clk,
    input  wire rst,
    input  wire start,
    input  wire [15:0] radicand,
    output reg  [7:0]  sqrt_out,
    output reg  done
);

reg [7:0]  root;
reg [3:0]  bit_pos;
reg running;
reg [15:0] rad_reg;

wire [7:0]  trial_root = root | (8'd1 << bit_pos[2:0]);
wire [15:0] trial_sq   = trial_root * trial_root;
wire        can_set    = (rad_reg >= trial_sq);

always @(posedge clk or posedge rst) begin
    if (rst) begin
        sqrt_out <= 8'd0;
        done     <= 1'b0;
        root     <= 8'd0;
        bit_pos  <= 4'd0;
        running  <= 1'b0;
        rad_reg  <= 16'd0;
    end else begin
        done <= 1'b0;
        
        if (start && !running) begin
            root    <= 8'd0;
            bit_pos <= 4'd7;
            running <= 1'b1;
            rad_reg <= radicand;
        end
        
        if (running) begin
            if (can_set)
                root <= trial_root;
            
            if (bit_pos == 4'd0) begin
                // Output the final trial_root (including this step's bit)
                sqrt_out <= can_set ? trial_root : root;
                done     <= 1'b1;
                running  <= 1'b0;
            end else begin
                bit_pos <= bit_pos - 4'd1;
            end
        end
    end
end

endmodule

🔬 仿真说明

仿真环境与策略

测试4组数据:(1) sqrt(144)=12 (2) sqrt(65535)=255 (3) sqrt(0)=0 (4) sqrt(100)=10。8周期完成计算,结果与Python math.isqrt一致。

✅ 验证结果

Verilator 5.020 仿真通过

本实验所有Verilog代码已通过Verilator编译验证,功能行为正确。测试用例覆盖核心功能路径,确保设计满足规格要求。

⚠️ 常见错误

🌍 真实世界

工业应用

开方器在3D图形(向量归一化)、通信(RMS计算)、控制系统中广泛使用。GPU每个ALU内置快速开方/逆开方单元。2024年NVIDIA Blackwell架构的SFPU支持单周期开方。FPGA中常用CORDIC替代Newton法避免除法器。

💡 扩展挑战

🚀 自己动手

# 编译并运行
verilator --cc sqrt_newton.sv --exe sqrt_newton_tb.cpp --build -j 0
./obj_dir/Vsqrt_newton

🎯 试一试

修改参数

尝试修改代码中的关键参数,观察仿真结果变化:

  • 调整位宽,观察不同数据范围
  • 修改初始值/种子,观察不同起始条件
  • 改变时钟分频,测试不同速度

💡 Verilator会在位宽不匹配时给出Warning,这是学习的好机会

添加功能

在现有基础上增加新功能:

  • 添加新的输入信号和控制逻辑
  • 增加状态或修改状态转移条件
  • 扩展输出,增加更多显示信息

🔧 增量开发:每次只改一个地方,验证通过后再改下一个

📋 Verilog速查

语法说明示例
reg [7:0]8位寄存器reg [7:0] data;
wire组合逻辑连线wire valid = cnt > 5;
always @(posedge clk)时序逻辑上升沿触发
always @(*)组合逻辑敏感列表自动推导
localparam局部常量localparam DIV = 50000000;
case多分支选择注意default分支
$display仿真打印不可综合,仅仿真用

📊 性能指标

资源估算(FPGA参考)

本设计在典型FPGA上的资源占用估算:LUT约20-120个,FF约30-100个,无BRAM/DSP依赖(特殊模块除外)。时钟频率可达50-100MHz+。Verilator仿真速度约5-10M周期/秒。

← 上一课 📚 目录 下一课 →