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
问题分析
- Initial块内的非法赋值:在
initial块中使用assign语句给neg_ifmap赋值是错误的,assign是连续赋值语句,不能放在过程块内;且neg_ifmap作为reg类型,应在组合逻辑块中计算。 - 8位变量存储-X的溢出问题:当
ifmap为-128时,-ifmap=128,但8位有符号数范围是-128~127,无法表示128,用8位reg存储neg_ifmap会溢出,最终存储的还是-128,符号扩展后依然是负数,导致计算错误。 - 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
修正说明
- 移除非法赋值逻辑:删除原
initial块内的错误assign语句,所有计算移到always @(*)组合逻辑块中。 - 避免8位变量溢出:不再使用8位
neg_ifmap,直接对16位符号扩展后的ifmap进行取反加1操作,可正确表示-(-128)=128(16位为16'b0000000010000000)。 - 规范Booth编码逻辑:用3位寄存器存储编码组合,严格遵循改进型Booth的编码规则映射操作,分组逻辑更清晰。
- 简化移位累加:将移位操作直接整合到累加步骤中,逻辑更简洁易懂。
原测试平台无需修改,运行修正后的代码后,-128输入的计算错误将被修复。
内容的提问来源于stack exchange,提问作者K.S.
相关产品推荐
相关产品推荐

