32位Verilog模运算模块部分计算异常问题咨询
32位Verilog模运算模块错误排查与修复
你实现的32位模运算模块仅能正确处理部分简单用例(如95 mod 12、5 mod 10),但在计算100 mod 7、255 mod 7时结果错误,核心问题出在两个关键逻辑上:
问题分析
1. start信号持续有效打断减法循环
模块中,start持续高电平时,每一个时钟上升沿都会执行temp <= A,导致减法操作被反复重置。比如测试用例里start = 1持续了100ns(对应10个时钟周期),每次时钟沿都把temp重新设为100,根本无法完成连续的temp - B循环,自然得不到正确结果。
2. done信号误触发
当前done直接由temp < B赋值,在减法过程中只要某一时刻temp小于B就会输出高电平,但这个信号没有考虑start阶段的状态,而且在减法循环未完全结束时可能提前触发,导致结果读取时机错误。
修复方案
修改后的模块代码
module mod_dp_32bit ( input wire clk, input wire rst, input wire start, input wire [31:0] A, input wire [31:0] B, output reg done, output wire [31:0] result ); reg [31:0] temp; reg running; // 新增状态标记,记录是否处于减法循环中 always @(posedge clk or posedge rst) begin if (rst) begin temp <= 32'b0; running <= 1'b0; done <= 1'b0; end else if (start) begin temp <= A; running <= 1'b1; done <= 1'b0; // 启动时置低done end else if (running) begin if (temp >= B) begin temp <= temp - B; done <= 1'b0; end else begin running <= 1'b0; done <= 1'b1; // 循环结束,置高done end end end assign result = temp; endmodule
关键修改点
- 新增
running状态寄存器:标记模块是否处于减法计算阶段,避免start持续有效时的重置问题,同时确保减法循环完整执行。 - 调整
done信号逻辑:只有当减法循环完全结束(running置低且temp < B)时,done才会置高,避免提前触发。 - 限制
start的作用:仅在start第一次有效时初始化temp,后续时钟沿不再重复赋值。
调整测试代码
测试代码中start只需给出一个时钟周期的高电平,避免持续触发重置:
`timescale 1ns/1ns module Mod32_TB; reg clk; reg rst; reg start; reg [31:0] A; reg [31:0] B; wire done; wire [31:0] result; // Instantiate mod_dp_32bit module mod_dp_32bit uut ( .clk(clk), .rst(rst), .start(start), .A(A), .B(B), .done(done), .result(result) ); // Clock generation initial begin clk = 0; forever #5 clk = ~clk; end // Test Case 1: 100 mod 7 = 2 initial begin // Initialize inputs rst = 1; A = 100; B = 7; start = 0; // Release reset #10 rst = 0; // 仅给一个时钟周期的start信号 #5 start = 1; #10 start = 0; // 等待done信号置高再读取结果 wait(done); $display("Test Case 1 Result: 100 mod 7 = %d", result); // Test Case 2: 255 mod 7 = 3 #10 A = 255; B = 7; start = 1; #10 start = 0; wait(done); $display("Test Case 2 Result: 255 mod 7 = %d", result); // Test Case 3: 95 mod 12 = 11 #10 A = 95; B = 12; start = 1; #10 start = 0; wait(done); $display("Test Case 3 Result: 95 mod 12 = %d", result); // End simulation $stop; end endmodule
测试代码调整点
- 初始
rst设为1,然后释放重置,符合模块的复位逻辑。 start仅保持一个时钟周期(10ns),确保temp只被初始化一次。- 使用
wait(done)等待计算完成后再读取结果,避免提前读取未完成的数值。
内容的提问来源于stack exchange,提问作者antonchekhov
相关产品推荐
相关产品推荐

