More than a year ago I faced a strange issue with a hardware design on a Virtex-5 FPGA. Basically an addition of multiple values had no effect at all. Out of curiosity I reproduced this issue and now here are the details about what seems to be a serious bug in the XST synthesis tool for Virtex-5 FPGAs bundled with ISE 14.7.
Let’s have a look at the following module:
module example( input wire CLK, input wire [1:0] in, output reg [2:0] out = 0, output reg [2:0] out_broken = 0 ); always @(posedge CLK) begin out_broken <= out_broken + in + 1; out <= out + {1'b0,in} + 1; end endmodule
Clearly, out and out_broken should always have the same value. This will be confirmed by a behavioral simulation. Take the following testbench as an example:
`timescale 1 ns/1 ps module example_tb; reg CLK; reg [1:0] in; wire [2:0] out; wire [2:0] out_broken; example uut ( .CLK(CLK), .in(in), .out(out), .out_broken(out_broken) ); initial begin CLK = 0; in = 2'b11; end always #1 CLK = ~CLK; endmodule
in is set to 3 so out and out_broken should be increased by 4 on every clock cycle, which is exactly what the behavioral simulation shows:
But if you run XST for a synthesis and do a post-translate simulation you will see out_broken just staying constant. This is not a bug in the post-translate simulation but can actually be observed on hardware:
So, what is happening here? To be sure you would have to look at the netlist generated by XST but one is left with the suspicion that in+1 translates to 0 and therefore out_broken <= out_broken. By adding another bit in front of in you can work around this issue.
If you set the implementation target to Virtex-6 or any newer device this issue disappears, so the underlying bug was eventually fixed by Xilinx. Consequently the Vivado tools are not affected at all. But if you are still designing for Virtex-5 this can really ruin your day…