项目场景:
一个8通道数据输入场景,所有代码需要写8遍,为了代码简洁使用了for语句,仿真正确,上板验证功能异常
问题描述
使用modelsim仿真一切正常,vivado编译后上板测试异常。仿真testbench输入两个512bit数据,第二个数伴随EOF表示数据结束,随后将这2个数写入DDR。所以DDR写请求时正确的长度应该是2.这里modelsim仿真确实是2,但上板验证时发现ila抓到的请求长度却是64.
always @(posedge DDR_USR_CLK)begin
if ( DDR_USR_RST )begin
r_CAP_DDR_WR_LEN <= 13'd0 ;
end else if (s_FSM_WR_REQ) begin
if(r_CH_WR_REQ[0]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[0] ? {r_CNT0 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[1]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[1] ? {r_CNT1 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[2]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[2] ? {r_CNT2 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[3]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[3] ? {r_CNT3 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[4]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[4] ? {r_CNT4 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[5]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[5] ? {r_CNT5 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[6]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[6] ? {r_CNT6 + 1'b1} : 13'd64 ;
end else if(r_CH_WR_REQ[7]) begin
r_CAP_DDR_WR_LEN <= r_LAST_LEN_REQ_DFF2[7] ? {r_CNT7 + 1'b1} : 13'd64 ;
end
end
end
编译太慢,本来想通过ECO直接去修改ila的probe,发现搜索不到r_LAST_LEN_REQ_DFF2这个寄存器,一分析难道是被优化了?如果是那长度就永远是64了。
再看r_LAST_LEN_REQ_DFF2的由来,是为了代码简洁在一个for块里产生的。
generate
genvar i;
for (i=0;i<8;i=i+1)
begin :u_delay_eof_req
delay_proc
#(
.DWIDTH (1 ) ,
.DLEN (1000 )
)u_delay_last_req(
.w_clk_i (CLK),
.reset_i (RST),
.d_i (CH_DATA_VLD_EOF[i]),
.d_o (s_CH_DATA_DLY_EOF[i])
);
always @ (posedge CLK ) begin
if (RST) begin
r_LAST_LEN_REQ <= 'b0 ;
end else if(~r_REG_CAPTURE_EN_D2) begin
r_LAST_LEN_REQ <= 'b0 ;
end else if( s_CH_DATA_DLY_EOF[i] )begin
r_LAST_LEN_REQ[i] <= 1'b1 ;
end
end
always @ (posedge DDR_USR_CLK ) begin
r_LAST_LEN_REQ_DFF1[i] <= r_LAST_LEN_REQ[i] ;
r_LAST_LEN_REQ_DFF2[i] <= r_LAST_LEN_REQ_DFF1[i] ;
end
end
endgenerate
回头一去看vivado的警告发现
[Synth 8-6859] multi-driven net on pin Q with 1st driver pin 'u_delay_eof_req[7].r_LAST_LEN_REQ_reg[6]/Q' ["E:/.../CAP_BUF.v":463]
modelsim vlog编译未给出警告
vlog -work work -L mtiAvm -L mtiRnm -L mtiOvm -L mtiUvm -L mtiUPF -L infact C:/Users/nuchu/Desktop/sim_prj/CAP_BUF.v
# Model Technology ModelSim SE-64 vlog 2020.4 Compiler 2020.10 Oct 13 2020
# Start time: 16:54:24 on Feb 21,2023
# vlog -reportprogress 300 -work work -L mtiAvm -L mtiRnm -L mtiOvm -L mtiUvm -L mtiUPF -L infact C:/Users/.../Desktop/sim_prj/CAP_BUF.v
# -- Compiling module CAP_BUF
#
# Top level modules:
# CAP_BUF
# End time: 16:54:24 on Feb 21,2023, Elapsed time: 0:00:0
原因分析:
r_LAST_LEN_REQ在for中RST时被赋值了8次,modelsim综合器和vivado综合器对此处理方式不一样,vivado直接给优化了导致功能异常。
所以给我们的启示,
一、以后modelsim即使仿真pass了,vivado综合后也还是要去关注vivado给出的警告。
二、慎用FOR语句,一定仔细再仔细。
解决方案:
generate
genvar i;
for (i=0;i<8;i=i+1)
begin :u_delay_eof_req
delay_proc
#(
.DWIDTH (1 ) ,
.DLEN (1000 )
)u_delay_last_req(
.w_clk_i (CLK),
.reset_i (RST),
.d_i (CH_DATA_VLD_EOF[i]),
.d_o (s_CH_DATA_DLY_EOF[i])
);
always @ (posedge CLK ) begin
if (RST) begin
r_LAST_LEN_REQ[i] <= 'b0 ;
end else if(~r_REG_CAPTURE_EN_D2) begin
r_LAST_LEN_REQ[i] <= 'b0 ;
end else if( s_CH_DATA_DLY_EOF[i] )begin
r_LAST_LEN_REQ[i] <= 1'b1 ;
end
end
always @ (posedge DDR_USR_CLK ) begin
r_LAST_LEN_REQ_DFF1[i] <= r_LAST_LEN_REQ[i] ;
r_LAST_LEN_REQ_DFF2[i] <= r_LAST_LEN_REQ_DFF1[i] ;
end
end
endgenerate