The problem is an inconsistency I observed when I compared the result of the synthesis step to the result of the P&R step. The P&R inserts a combinatorial loop which is not present in the synthesis step. The tool flags then for the loop issue in the P&R trace report. I could make the problem disappear by resetting the variable properly but I haven't really grasped why the loop buffer is inserted.
I simplified the VHDL code in question for the purpose of this post. It is a legacy code that resets an internal variable to the value of an input pin, which I suspect to be a bug.
ENTITY InjectCtrl IS
PORT
(
Reset : in STD_LOGIC;
clk : in STD_LOGIC;
inject : in STD_LOGIC;
injector_opens : out STD_ULOGIC;
injector_closes : out STD_ULOGIC
);
END ENTITY;
architecture rtl of InjectCtrl is
begin
Process(Reset, clk)
Variable Delayed_Inject : STD_LOGIC;
Begin
if reset = '0' then
injector_opens <= '0';
injector_closes <= '0';
Delayed_Inject := '0';
Delayed_Inject := Inject; -- issue line
elsif rising_edge(clk) then
injector_opens <= '0';
injector_closes <= '0';
if (Delayed_Inject = '0') then
injector_opens <= '0';
injector_closes <= '1';
else
injector_opens <= '1';
injector_closes <= '0';
end if;
Delayed_Inject := Inject;
end if;
end Process;
end architecture;
The generated RTL diagram looks like this.
The diagram seems to be in line with what the code is specifying. The variable Delayed_Inject
samples the value of the inject
input every clock cycle, hence the flip-flop. However when the reset signal is de-asserted (reset = '0'), the variable is not set to '0', but instead to the value of the input signal inject
. This explains why inject
is routed through logic to the SET pin of the flip-flop. So at reset, if inject
input is high, RESET pin is low and SET pin is high, which results in an output from the flip-flop being also high. Inversely, if inject
is low, RESET pin is high and SET pin is low which gives a low output (D FF with set and reset pin).
The technology view diagrams looks a bit different from what I have expected.
First, notice the inference of two flip-flops for Delayed_Inject
instead of one. But what is most interesting is the inference of a loop buffer that is routing the output of the LUT_3222 to itself. Where does that loop come from?
For reference, I am using Lattice Diamond with Synplify as synthesis tool of choice. The target FPGA is from the LFE5U family.