You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

8位无符号改进型Booth乘法器MAC输入-128时的错误解决求助

解决8位改进型Booth乘法器MAC模块中-128输入的错误问题

我刚开始学习Verilog,尝试实现一个包含8位有符号改进型Booth乘法器的MAC(乘累加)模块,但当输入为-128(二进制8'b10000000)时出现计算错误,推测是-128在二进制补码运算中的特殊性质导致的问题。

以下是原MAC模块代码:

module MAC(
    input [7:0] ifmap,   // Input feature map
    input [7:0] filter,  // Filter
    input [23:0] psum,   // Partial sum
    output reg [23:0] updated_psum  // Updated partial sum
);

    reg  [15:0] p, ans;
    reg  [7:0] neg_ifmap;
    reg [23:0] prod;
    integer i, lookup_tbl, operate;
    
    initial begin
        p = 16'b0;
        ans = 16'b0;
        // Two's complement of a negative number
        assign neg_ifmap = (~ifmap) + 1;
    end

    always @(*) begin
        p = 16'b0;
        
        for (i = 1; i <= 7; i = i + 2) begin
            if (i == 1)
                lookup_tbl = 0;
            else
                lookup_tbl = filter[i-2];

            lookup_tbl = lookup_tbl + 4*filter[i] + 2*filter[i-1];

            if (lookup_tbl == 0 || lookup_tbl == 7)
                operate = 0;
            else if (lookup_tbl == 3 || lookup_tbl == 4)
                operate = 2;
            else
                operate = 1;

            if (filter[i] == 1) 
               operate = -1*operate;
                
            case (operate)
            1: begin
                ans = {{8{ifmap[7]}}, ifmap};
                ans = ans << (i-1);
                p = p + ans;
            end
            2: begin
                ans = {{8{ifmap[7]}}, ifmap} << 1;
                ans = ans << (i-1);
                p = p + ans;
            end
            -1: begin
                ans = {{8{neg_ifmap[7]}}, neg_ifmap};
                ans = ans << (i-1);
                p = p + ans;
            end
            -2: begin
                ans = {{8{neg_ifmap[7]}}, neg_ifmap} << 1; // negative a
                ans = ans << (i - 1);
                p = p + ans;
            end
            endcase

        end
        prod = {{8{p[15]}}, p};
        updated_psum <= prod + psum;
    end
endmodule

原测试平台代码:

`include "MAC.v"

module MAC_tb;
    reg signed [7:0]   a;
    reg signed [7:0]   b;
    reg signed [23:0]  c;
    wire [23:0] result;
    
    
    MAC MAC0(
        .ifmap(a),
        .filter(b),
        .psum(c),
        .updated_psum(result)
    );
  
    reg signed [23:0] answer;
    reg signed [23:0]  test_c[4:0];
    
    integer i, j, k;
    integer err;
    
    initial begin
        `ifdef FSDB
            $fsdbDumpfile("MAC.fsdb");
            $fsdbDumpvars("+struct", "+mda", MAC0);
        `endif

        test_c[0] = {24{1'b1}};
        test_c[1] = 24'b0;
        test_c[2] = 24'b0101_0101_0101_0101_0101_0101;
        test_c[3] = 24'b1010_1010_1010_1010_1010_1010;
        test_c[4] = 24'b0011_0011_0011_0011_0011_0011;
        err = 0;
        for (i = 8'b0; i <= 8'b1111_1111; i = i+1) begin
            for (j = 8'b0; j <= 8'b1111_1111; j = j+1) begin
                for (k = 8'd0; k <= 8'd4; k = k+1) begin
                    a = i;
                    b = j;
                    c = test_c[k]; 
                    answer = a * b + c;
                    #100
                    if(answer != result) begin
                        $display("Error      :%d*%d+%d=%d", a, b, c, answer);
                        $display("Your result:%d*%d+%d=%d", a, b, c, $signed(result));
                        err = err + 1;
                    end else begin
                        err = err;
                    end
                end
            end
        end
        $display("Error times:%d", err);
    end

endmodule

问题分析

  1. Initial块内的非法赋值:在initial块中使用assign语句给neg_ifmap赋值是错误的,assign是连续赋值语句,不能放在过程块内;且neg_ifmap作为reg类型,应在组合逻辑块中计算。
  2. 8位变量存储-X的溢出问题:当ifmap为-128时,-ifmap=128,但8位有符号数范围是-128~127,无法表示128,用8位reg存储neg_ifmap会溢出,最终存储的还是-128,符号扩展后依然是负数,导致计算错误。
  3. Booth编码的逻辑偏差:原代码用整数运算计算编码值,容易出现逻辑映射错误,且分组方式不够清晰。

修正后的MAC模块代码

module MAC(
    input [7:0] ifmap,   // 输入特征图(有符号)
    input [7:0] filter,  // 滤波器系数(有符号)
    input [23:0] psum,   // 部分和(有符号)
    output reg [23:0] updated_psum  // 更新后的部分和(有符号)
);

    reg  [15:0] p, ans;
    reg [23:0] prod;
    integer i;
    reg [2:0] booth_code; // 用3位存储Booth编码,避免整数运算误差
    
    always @(*) begin
        p = 16'b0;
        
        // 改进型Booth乘法:给filter补最低位0,分成4组三位编码
        for (i = 0; i < 8; i = i + 2) begin
            // 构造三位编码:filter[i+1], filter[i], 前一位(初始为0)
            booth_code = (i == 0) ? {filter[1], filter[0], 1'b0} : {filter[i+1], filter[i], filter[i-1]};
            
            // 按Booth编码规则执行对应操作
            case (booth_code)
                3'b000, 3'b111: ans = 16'b0;                  // +0,无操作
                3'b001, 3'b010: ans = {{8{ifmap[7]}}, ifmap}; // +X,符号扩展为16位
                3'b011: ans = {{8{ifmap[7]}}, ifmap} << 1;    // +2X,符号扩展后左移
                3'b100: ans = (~{{8{ifmap[7]}}, ifmap} + 1) << 1; // -2X,取反加1后左移
                3'b101, 3'b110: ans = ~{{8{ifmap[7]}}, ifmap} + 1; // -X,取反加1
            endcase
            
            // 移位到对应位并累加
            p = p + (ans << i);
        end
        
        // 将16位乘积符号扩展为24位,与部分和累加
        prod = {{8{p[15]}}, p};
        updated_psum = prod + psum;
    end
endmodule

修正说明

  1. 移除非法赋值逻辑:删除原initial块内的错误assign语句,所有计算移到always @(*)组合逻辑块中。
  2. 避免8位变量溢出:不再使用8位neg_ifmap,直接对16位符号扩展后的ifmap进行取反加1操作,可正确表示-(-128)=128(16位为16'b0000000010000000)。
  3. 规范Booth编码逻辑:用3位寄存器存储编码组合,严格遵循改进型Booth的编码规则映射操作,分组逻辑更清晰。
  4. 简化移位累加:将移位操作直接整合到累加步骤中,逻辑更简洁易懂。

原测试平台无需修改,运行修正后的代码后,-128输入的计算错误将被修复。

内容的提问来源于stack exchange,提问作者K.S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:17:24