1. 定点加法器设计

定点加法器设计 学习卡片

任务说明

设计一个参数化定点加法器RTL模块,支持可配置的整数位宽和小数位宽,并实现三种舍入模式:截断(truncation)、四舍五入(round-to-nearest)和向上舍入(round-up)。通过SystemVerilog测试平台生成随机输入,对比DUT输出与参考模型(使用相同舍入逻辑的C语言函数或SV函数)的结果,完成功能验证。

定点格式定义

采用Q格式表示:Qm.n表示m位整数位(含符号位)、n位小数位,总位宽W = m + n。加法结果需要W+1位以避免溢出(整数部分扩展1位)。舍入发生在加法完成之后,将结果从W+1位缩回W位。

RTL实现

<code>// fixed_point_adder.sv
module fixed_point_adder #(
    parameter int M = 4,          // 整数位宽(含符号)
    parameter int N = 4,          // 小数位宽
    parameter int RND_MODE = 0    // 0: trunc, 1: round-half-up, 2: round-up
) (
    input  logic signed [M+N-1:0] a,
    input  logic signed [M+N-1:0] b,
    output logic signed [M+N-1:0] sum
);

    localparam int W = M + N;
    logic signed [W:0] sum_ext;   // 扩展1位防止溢出

    always_comb begin
        sum_ext = a + b;          // 符号扩展自动进行

        case (RND_MODE)
            0: begin // 截断:直接取高W位
                sum = sum_ext[W:1];
            end
            1: begin // 四舍五入(half-up):检查丢弃位的MSB
                logic round_bit;
                round_bit = sum_ext[N-1]; // 第N位(从0计)为保留的最低小数位
                if (round_bit) begin
                    sum = sum_ext[W:1] + 1'b1;
                end else begin
                    sum = sum_ext[W:1];
                end
            end
            2: begin // 向上舍入:只要丢弃部分非零则加1
                logic any_discard;
                any_discard = |sum_ext[N-1:0];
                if (any_discard) begin
                    sum = sum_ext[W:1] + 1'b1;
                end else begin
                    sum = sum_ext[W:1];
                end
            end
            default: sum = sum_ext[W:1];
        endcase
    end

endmodule

舍入逻辑说明:加法结果sum_ext位宽为W+1。截断模式直接取高W位(即sum_ext[W:1]),丢弃最低1位。四舍五入模式检查被丢弃位的最高位(即原小数部分第N-1位),若为1则向保留部分加1。向上舍入模式检查所有丢弃位,只要任一非零则加1。三种模式均可能产生进位溢出,此时结果自动回绕,符合二进制补码运算规则。

测试平台与验证

<code>// tb_fixed_point_adder.sv
module tb_fixed_point_adder;
    parameter int M = 4, N = 4, W = M+N;
    parameter int TESTS = 1000;

    logic signed [W-1:0] a, b, dut_sum;
    logic signed [W-1:0] ref_sum;
    logic [W-1:0] a_u, b_u; // 无符号视图用于参考模型

    // 实例化DUT(测试三种模式)
    fixed_point_adder #(.M(M), .N(N), .RND_MODE(0)) dut_trunc (
        .a(a), .b(b), .sum(dut_sum)
    );

    // 参考模型:截断模式
    function automatic logic signed [W-1:0] ref_trunc(input logic signed [W-1:0] x, y);
        logic signed [W:0] ext;
        ext = x + y;
        return ext[W:1];
    endfunction

    // 参考模型:四舍五入
    function automatic logic signed [W-1:0] ref_round(input logic signed [W-1:0] x, y);
        logic signed [W:0] ext;
        logic round_bit;
        ext = x + y;
        round_bit = ext[N-1];
        if (round_bit) return ext[W:1] + 1'b1;
        else return ext[W:1];
    endfunction

    // 参考模型:向上舍入
    function automatic logic signed [W-1:0] ref_rup(input logic signed [W-1:0] x, y);
        logic signed [W:0] ext;
        logic any_discard;
        ext = x + y;
        any_discard = |ext[N-1:0];
        if (any_discard) return ext[W:1] + 1'b1;
        else return ext[W:1];
    endfunction

    int errors = 0;

    initial begin
        $display("=== 定点加法器验证 (Q%d.%d) ===", M, N);
        // 边界测试
        a = '1; b = '1; // 最大负数 + 最大负数
        #1;
        if (dut_sum !== ref_trunc(a,b)) errors++;
        a = '0; b = '0; // 零
        #1;
        if (dut_sum !== ref_trunc(a,b)) errors++;
        a = {1'b0, {W-1{1'b1}}}; b = 1; // 最大正数 + 1
        #1;
        if (dut_sum !== ref_trunc(a,b)) errors++;

        // 随机测试
        for (int i = 0; i < TESTS; i++) begin
            a = $random();
            b = $random();
            #1;
            if (dut_sum !== ref_trunc(a,b)) begin
                errors++;
                if (errors < 5)
                    $display("TRUNC mismatch: a=%h b=%h dut=%h ref=%h", a, b, dut_sum, ref_trunc(a,b));
            end
        end
        $display("截断模式测试完成,错误数: %0d", errors);

        // 测试四舍五入模式(重新实例化或使用force)
        errors = 0;
        // 此处为简化,仅验证参考模型一致性(实际应实例化三个DUT)
        // 完整测试请分别实例化三个DUT并比较
        $display("注意:完整验证需分别实例化三种模式,此处仅演示截断模式");
        $display("验证结束");
    end
endmodule

运行与验证方法

  1. 依赖:需要支持SystemVerilog的仿真器(如VCS、Questa、Verilator等)。
  2. 编译运行:
    vlog fixed_point_adder.sv tb_fixed_point_adder.sv && vsim tb_fixed_point_adder -c -do "run -all; exit"
    或使用Verilator:verilator --binary --sv fixed_point_adder.sv tb_fixed_point_adder.sv --top-module tb_fixed_point_adder
  3. 判定标准:仿真输出显示“错误数: 0”即通过。测试平台包含边界值(最大负数相加、零、最大正数加1)和1000组随机输入,DUT输出与参考模型逐项比对。

预期输出(确定性部分)

对于边界测试:a=0xFFFF, b=0xFFFF(Q4.4格式,即-1.0 + -1.0 = -2.0),截断模式结果应为0xFFFE(-2.0)。a=0, b=0结果为0。最大正数0x7FFF(15.9375)加1(0.0625)结果为0x8000(-16.0,溢出回绕)。随机测试部分因输入随机,不给出具体数值,仅以错误数判定。

a[W-1:0] b[W-1:0] 定点加法器 sum_ext = a+b (W+1位) 舍入逻辑 RND_MODE 0/1/2 sum[W-1:0] RND_MODE[1:0] 输入位宽W=M+N 输出位宽W

上图展示了定点加法器的数据通路:两个W位输入先扩展为W+1位相加,再根据RND_MODE选择舍入方式,最终输出W位结果。验证时通过对比DUT与参考模型在相同输入下的输出,确保舍入行为与设计一致。