可变输出流延迟模块异常:行为仿真正常但综合后失效
脉冲延迟模块综合失效问题排查与修复
需求与问题现状
- 模块需求:处理脉冲间隔为500-12500 clk周期的数据流,将其延迟指定的500-12500 clk周期,禁止使用12500位移位寄存器。
- 当前问题:Verilog代码行为仿真正常,但综合后功能完全失效,原理图仅保留输出缓冲与引脚,仿真无输出。
- 设计思路:用25个14位寄存器存储脉冲间隔,等待指定延迟后按存储信息输出,通过
unusedStorage标记已使用的存储项。
原代码
module data_delay_counter( input clk, input en, input [13:0] ShiftNum, input s_IN, output reg s_OUT ); // counting phase reg [13:0] cyclesToInputPulse = 0; // counted clk cycles before a pulse // storage phase reg [4:0] memoryIndxWrite = 0; // index to write pulse information to reg [13:0] storage [0:24]; // memory for pulse information // delay phase reg [13:0] delayCounter = 0; // output delay counter // output phase reg [4:0] memoryIndxRead = 0; // index to read out pulse information from reg [13:0] cyclesToOutputPulse = 0; // counted clk cycles up to number read out from storage reg [24:0] unusedStorage = 0; // specifies if storage pulse info has been used or not, 1 for unused 0 for used always @(posedge clk) begin if (en == 1) begin // counting phase if (s_IN != 1) cyclesToInputPulse = cyclesToInputPulse + 14'd1; else begin // storage phase cyclesToInputPulse = cyclesToInputPulse + 14'd1; storage[memoryIndxWrite] = cyclesToInputPulse; unusedStorage[memoryIndxWrite] = 1; cyclesToInputPulse = 14'd0; memoryIndxWrite = memoryIndxWrite + 14'd1; if (memoryIndxWrite == 25) memoryIndxWrite = 14'd0; end // delay phase if (delayCounter != ShiftNum) delayCounter = delayCounter + 1; // output phase else begin cyclesToOutputPulse = cyclesToOutputPulse + 14'd1; if (cyclesToOutputPulse == storage[memoryIndxRead] && unusedStorage[memoryIndxRead] == 1) begin s_OUT = 1; unusedStorage[memoryIndxRead] = 0; cyclesToOutputPulse = 14'd0; memoryIndxRead = memoryIndxRead + 14'd1; if (memoryIndxRead == 25) memoryIndxRead = 0; end else begin s_OUT = 0; end end end else begin cyclesToInputPulse = 0; memoryIndxWrite = 0; delayCounter = 0; cyclesToOutputPulse = 0; memoryIndxRead = 0; unusedStorage = 0; s_OUT = 0; end end always @(ShiftNum) begin cyclesToInputPulse = 0; memoryIndxWrite = 0; delayCounter = 0; cyclesToOutputPulse = 0; memoryIndxRead = 0; unusedStorage = 0; s_OUT = 0; end
代码问题分析
多驱动冲突
同一个寄存器(如cyclesToInputPulse、memoryIndxWrite)同时被always @(posedge clk)时序块和always @(ShiftNum)组合逻辑块驱动,违反Verilog单驱动规则。综合工具无法处理这种冲突,会直接优化掉相关逻辑,导致功能完全丢失。阻塞赋值错误
时序逻辑块中全部使用阻塞赋值(=),而非标准的非阻塞赋值(<=)。虽然行为仿真可能正常,但综合时会破坏寄存器的同步更新机制,导致逻辑被错误优化或功能异常。位宽不匹配与边界错误
- 5位的
memoryIndxWrite/memoryIndxRead自增时使用14位的14'd1,位宽不匹配引发隐式类型转换,可能导致综合工具误判。 - 地址边界判断
memoryIndxWrite == 25错误:0-24共25个存储单元,最大值是24而非25,会导致索引越界。
- 5位的
存储单元未显式初始化
数组storage未显式初始化,综合时可能被视为无关项优化,导致存储的数据不可靠。
修复后的代码
module data_delay_counter( input clk, input en, input [13:0] ShiftNum, input s_IN, output reg s_OUT ); // counting phase reg [13:0] cyclesToInputPulse = 14'd0; // counted clk cycles before a pulse // storage phase reg [4:0] memoryIndxWrite = 5'd0; // index to write pulse information to reg [13:0] storage [0:24]; // memory for pulse information // delay phase reg [13:0] delayCounter = 14'd0; // output delay counter // output phase reg [4:0] memoryIndxRead = 5'd0; // index to read out pulse information from reg [13:0] cyclesToOutputPulse = 14'd0; // counted clk cycles up to number read out from storage reg [24:0] unusedStorage = 25'd0; // specifies if storage pulse info has been used or not, 1 for unused 0 for used // 检测ShiftNum变化实现复位 reg [13:0] ShiftNum_r = 14'd0; always @(posedge clk) begin // 捕获ShiftNum的上一周期值 ShiftNum_r <= ShiftNum; // 复位逻辑优先:en低电平或ShiftNum变化时复位 if (!en || (ShiftNum != ShiftNum_r)) begin cyclesToInputPulse <= 14'd0; memoryIndxWrite <= 5'd0; delayCounter <= 14'd0; cyclesToOutputPulse <= 14'd0; memoryIndxRead <= 5'd0; unusedStorage <= 25'd0; s_OUT <= 1'b0; end else begin // counting phase if (s_IN != 1'b1) begin cyclesToInputPulse <= cyclesToInputPulse + 14'd1; end else begin // storage phase cyclesToInputPulse <= cyclesToInputPulse + 14'd1; storage[memoryIndxWrite] <= cyclesToInputPulse; unusedStorage[memoryIndxWrite] <= 1'b1; cyclesToInputPulse <= 14'd0; // 修正位宽匹配 memoryIndxWrite <= memoryIndxWrite + 5'd1; if (memoryIndxWrite == 5'd24) begin memoryIndxWrite <= 5'd0; end end // delay phase if (delayCounter != ShiftNum) begin delayCounter <= delayCounter + 14'd1; end // output phase if (delayCounter == ShiftNum) begin cyclesToOutputPulse <= cyclesToOutputPulse + 14'd1; if (cyclesToOutputPulse == storage[memoryIndxRead] && unusedStorage[memoryIndxRead] == 1'b1) begin s_OUT <= 1'b1; unusedStorage[memoryIndxRead] <= 1'b0; cyclesToOutputPulse <= 14'd0; // 修正位宽匹配 memoryIndxRead <= memoryIndxRead + 5'd1; if (memoryIndxRead == 5'd24) begin memoryIndxRead <= 5'd0; end end else begin s_OUT <= 1'b0; end end else begin s_OUT <= 1'b0; end end end endmodule
修复要点
- 移除多驱动冲突:删除独立的
always @(ShiftNum)组合逻辑块,将ShiftNum变化时的复位逻辑整合到时钟沿的时序块中,通过检测ShiftNum的前后值变化实现复位。 - 替换为非阻塞赋值:时序逻辑中全部使用
<=,确保寄存器同步更新,符合综合工具的要求。 - 修正位宽与边界:所有自增和比较操作使用匹配的位宽,修正存储单元的索引边界判断(0-24)。
- 显式初始化:所有寄存器都显式初始化位宽和初始值,避免综合时的不确定优化。
内容的提问来源于stack exchange,提问作者FillenNaymeer
相关产品推荐
相关产品推荐

