nextpnr error: timing analysis failed due to presence of combinatorial loops
When switching from ArchnePnR to NextPnR I started to get some weird errors when synthesizing my FPGA projects. The same project was synthesizing apparently fine in arachnePnR, but I guess NextPnR is more picky about some aspect. I guess it’s better anyway, so the more warnings and errors we can get and fix, the more I’ll learn and the better I hope the design would be.
One error I got was:
ERROR: timing analysis failed due to presence of combinatorial loops, incomplete specification of timing ports, etc.
My reaction was to look at nextpnr output for some more indication about where the problem could be, but I was totally blind. So I headed to the #yosys channel on FreeNode, where are the awesome devs of Yosys, and some other experts, which usually are very helpful.
Their first hint was that Nextpnr maybe be complaining because of a combinational loop in its input, that is in the output of yosys, so that I should look at the yosys output for possible warnings.
Also they asked me if I had latches in your design? I wasn’t aware of having any latch, but I got another very useful hint: look for ‘Latch inferred’ in yosys log! That was spot on:
Indeed, grepping yosys’ output log I could find that a nasty latch has been infered:
Latch inferred for signal `\top.\hex_digit' from process `\top.$proc$top.v:66$35':
$auto$proc_dlatch.cc:417:proc_dlatch$495
Ok that was really something I could work with now! This pointed me to hex_digit
in top.v
. And there I could finally see it. Notice how hex_digit
doesn’t have a default value in the always() block (while char_shown
does):
always @(*) begin
char_shown = 8'h00;
if (activevideo2) begin
if ( px_x2 >> (3+`Zoom) == 10 && px_y2 >> (3+`Zoom) == 8 )
begin
hex_digit = counter[3:0];
char_shown = digit_ascii_code;
end
else if ( px_x2 >> (3+`Zoom) == 9 && px_y2 >> (3+`Zoom) == 8 )
begin
hex_digit = counter[7:4];
char_shown = digit_ascii_code;
end
end
end
After fixing it, like below, (notice the hex_digit = 4'b 0;
that gives a default value) I could finally pass the nextpnr step and synthesize fine!
always @(*) begin
char_shown = 8'h00;
hex_digit = 4'b 0;
if (activevideo2) begin
if ( px_x2 >> (3+`Zoom) == 10 && px_y2 >> (3+`Zoom) == 8 )
begin
hex_digit = counter[3:0];
char_shown = digit_ascii_code;
end
else if ( px_x2 >> (3+`Zoom) == 9 && px_y2 >> (3+`Zoom) == 8 )
begin
hex_digit = counter[7:4];
char_shown = digit_ascii_code;
end
end
end
Another finally tip that might come handy in this situation, in case you can’t find the origin of the error, is that you can run nextpnr with --ignore-loops
and it will simply ignore the error.