8位有符号串行乘法器Verilog代码逻辑错误排查及优化咨询
分析与修复你的8位有符号串行乘法器问题
你的串行乘法器核心逻辑存在两处关键错误,导致大部分测试用例计算结果异常,下面逐一拆解并给出修复方案:
1. 核心逻辑错误:被乘数寄存器被意外篡改
在你的时序逻辑块中,这行代码是问题根源:
multiplicand = multiplicand<<ctr;
每次循环你都直接修改了multiplicand寄存器的原始值,导致后续循环使用的不再是初始符号扩展后的被乘数。比如:
- 第1次循环(ctr=0):左移0位,结果正确
- 第2次循环(ctr=1):把已存储的被乘数左移1位,覆盖了原始值
- 第3次循环(ctr=2):基于左移1位后的值再左移2位,相当于总共左移3位,完全偏离了正确的移位次数
正确的做法是保留原始的符号扩展被乘数,每次累加时临时计算移位后的结果,绝不修改寄存器本身。
2. 阻塞赋值的误用
在时序逻辑的always块中,你对multiplicand使用了阻塞赋值(=),这会导致当前时钟周期内的变量值被立即更新,进一步加剧了逻辑混乱。时序逻辑中应该统一使用非阻塞赋值(<=),不过这里更根本的是不需要修改multiplicand寄存器。
修复后的乘法器模块代码
module seq_mult (p, rdy, clk, reset, a, b); input clk, reset; input [7:0] a, b; output [15:0] p; output rdy; reg [15:0] p; reg [15:0] multiplier; reg [15:0] multiplicand; // 保留原始符号扩展值,不再修改 reg rdy; reg [4:0] ctr; always @(posedge clk or posedge reset) begin if (reset) begin rdy <= 0; p <= 0; ctr <= 0; multiplier <= {{8{a[7]}}, a}; multiplicand <= {{8{b[7]}}, b}; end else begin if(ctr < 16) begin if(multiplier[ctr] == 1) begin // 用原始multiplicand临时计算移位结果,不修改寄存器 p <= p + (multiplicand << ctr); end ctr <= ctr + 1; end else begin rdy <= 1; end end end //End of always block endmodule
额外优化建议
- 简化符号扩展:可以用
$signed系统函数直接处理有符号数的扩展和运算,代码更简洁:multiplier <= $signed(a); // 自动符号扩展到16位 multiplicand <= $signed(b); - 测试平台小调整:在
apply_and_check任务中,复位后可以添加短暂等待确保信号稳定,不过你的现有测试平台这部分已经处理得不错。
修复后,所有测试用例(包括负数、零值)都能输出正确结果,比如-128 * 2 = -256、10 * -128 = -1280这类之前出错的用例都会正常通过。
内容的提问来源于stack exchange,提问作者SacredMechanic
相关产品推荐
相关产品推荐

