Vivado生成比特流时出现组合环错误的技术求助
问题概述
生成比特流时触发约100个组合环错误,涉及信号addr_121f、addr_store_1_f和addr_store_2_f。其中addr_store_2_f与addr_122f逻辑完全一致,但addr_122f未出现错误。
关键代码片段
// 简化后的赋值逻辑 // assign jump_1= (some signals)?(addr_121s == addr_store_1_f + some value) // assign jump_2= (some signals)?(addr_122s == addr_store_2_f + some value) assign input_last_addr_1 = addr_store_1_f + addr_temp_cal_2; assign input_last_addr_2 = addr_store_2_f + addr_temp_cal_2; assign last_addr_1 = (ram_cs == READ_FROM_S) ? addr_store_1_s + addr_temp_cal_1 : (ram_cs == READ_FROM_F) ? addr_store_1_f + addr_temp_cal_1 : input_last_addr_1; assign last_addr_2 = (ram_cs == READ_FROM_S) ? addr_store_2_s + addr_temp_cal_1 : (ram_cs == READ_FROM_F) ? addr_store_2_f + addr_temp_cal_1 : input_last_addr_2; assign jump_1= (conv_start) ? (ram_1_w_sd)? (ram_cs == READ_FROM_S) ? (addr_121s == last_addr_1):(addr_121f == last_addr_1) : 0 : 0; assign jump_2= (conv_start) ? (ram_2_w_sd)? (ram_cs == READ_FROM_S) ? (addr_122s == last_addr_2):(addr_122f == last_addr_2) : 0 : 0; assign addr_f_r_stop = !(cs==FIRST_ROW_SD && ram_1_w_sd && ram_cs == READ_FROM_SD); ///////////////////////////////////////////////////////////////////////// always@(posedge clk)begin//conv_b reading input from ram1 if( ram_cs==CLEAR_STATE || ram_cs==SD_TO_F || ram_cs==F_TO_F || ram_cs==F_TO_S || ram_cs == TO_OUT)begin//change 1 is one clk before READ_FROM_F addr_1f_r <= 1; addr_2f_r <= 0; addr_store_1_f <= 0; addr_store_2_f <= 0; end else if(ram_cs!= READ_FROM_S )begin //input valid high indicates that the conv_cell will take value and the input is valid to store if( addr_f_r_stop && conv_start && input_valid)begin if(ram_1_jump) addr_2f_r <= addr_2f_r + 1; if(ram_2_jump) addr_1f_r <= addr_1f_r + 1; end if(jump_1)begin addr_store_1_f <= addr_121f +1; end if(jump_2)begin addr_store_2_f <= addr_122f +1; end end end //////////////////////////////////////////////// assign addr_121f = (conv_start) ? ( wen_121f ) ? addr_121f_w : (input_valid) ? addr_1f_r : addr_121f : 0; ////////////////////////////////////////////////////
错误示例
ERROR: [DRC LUTLP-1] 组合环告警:1个LUT单元形成组合环,这会引发竞争条件,时序分析结果可能不准确。推荐的解决方式是修改设计移除组合逻辑环。如果确认该环路是预期且可接受的,可以通过对环路中的任意网表添加以下XDC约束来绕过DRC检查:
set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets <myHier/myNet>]。环路中的一个网表为:design_1_i/e_top_0/inst/conv_top_1/addr_store_2_f[28]_i_9_n_0。请评估你的设计。环路中的单元为:design_1_i/e_top_0/inst/conv_top_1/addr_store_2_f[28]_i_9。
错误原因分析
addr_121f的自赋值组合环:
最后一行addr_121f的连续赋值中,当conv_start为真、wen_121f为假且input_valid为假时,addr_121f直接赋值为自身,这是典型的组合逻辑环路——信号输出直接反馈到输入,综合工具会生成LUT形成闭环。addr_store_1_f与jump_1的循环依赖:
信号依赖链:addr_121f→jump_1→addr_store_1_f→last_addr_1→jump_1。整个链路完全由组合逻辑构成,没有时序寄存器打断,形成了更大的组合环路。addr_122f无错误的原因:
推测addr_122f的赋值逻辑没有自引用,也没有形成类似的组合依赖链,因此未触发错误。
解决方案
1. 修复addr_121f的自赋值问题
把addr_121f的组合逻辑改成时序逻辑,用寄存器寄存,避免自反馈:
reg addr_121f; always@(posedge clk)begin if(!conv_start) begin addr_121f <= 0; end else begin if(wen_121f) begin addr_121f <= addr_121f_w; end else if(input_valid) begin addr_121f <= addr_1f_r; end // 去掉原有的自赋值分支,寄存器会保持原值 end end
2. 打破jump_1与addr_store_1_f的组合环路
给jump_1或者addr_store_1_f增加一拍寄存,消除组合依赖:
比如把jump_1寄存后再驱动addr_store_1_f:
reg jump_1_reg; always@(posedge clk)begin jump_1_reg <= jump_1; end // 在always块中使用寄存后的信号 if(jump_1_reg)begin addr_store_1_f <= addr_121f +1; end
3. 临时规避(不推荐)
如果确认组合环是设计预期且无功能风险,可以添加XDC约束绕过DRC检查:
set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets design_1_i/e_top_0/inst/conv_top_1/addr_store_2_f[28]_i_9_n_0]
但这种方法会导致时序分析不准确,存在竞争风险,仅建议临时验证使用。
内容的提问来源于stack exchange,提问作者ENing

