2
\$\begingroup\$

Here is the code of a developer (let's ignore the name of the signals):

always_ff @(posedge clk) begin
  if (rst) begin
    buff_eop    <=  1;
  end else if (tx_usr_axis_tvalid & tx_usr_axis_tlast & tx_usr_axis_tready) begin
    buff_eop    <=  1;
  end else if (tx_usr_axis_tvalid & tx_usr_axis_tready) begin
    buff_eop    <=  0;
  end
end

Synthesis result:

fdresynthesis

Truth table of the LUT:

enter image description here

  • I'm unable to explain the developer why the code doesn't produce the correct behavior in hardware (but does it in simulation)

UUG974:

FDRE

Using a proper "else" doesn't solve anything:

always_ff @(posedge clk) begin
  if (rst) begin
    buff_eop    <=  1;
  end else begin
    if (tx_usr_axis_tvalid & tx_usr_axis_tlast & tx_usr_axis_tready) begin
      buff_eop    <=  1;
    end else if (tx_usr_axis_tvalid & tx_usr_axis_tready) begin
      buff_eop    <=  0;
    end
  end
end

Assumptions

  • The FDRE's reset value is 0, the compiler tries to synthesis that using LUT and a feedback.

    • Conclusion: Any registers have to be reset to 0 and nothing else, this should be a developer rule.
  • The only explanation I can have is looking at the logic table, it stays forever in the Q=D state that might be undefined (or 0 here) forever.

    • even though the reset signal (that isn't the FDRE's reset) is high, something prevent the FDRE to become high for whatever reason. Looking at the LUT's truth table, the output should be 1 when I4 (our rst signal) is high.
  • It works in simulation.

Test from nanofarad's comment:

module top(
    input logic clk,
    input logic rst,
    input logic tx_usr_axis_tvalid,
    input logic tx_usr_axis_tlast,
    input logic tx_usr_axis_tready
);

(*mark_debug="true"*)logic buff_eop;

always_ff @(posedge clk) begin
  if (rst) begin
    buff_eop    <=  1;
  end else if (tx_usr_axis_tvalid & tx_usr_axis_tlast & tx_usr_axis_tready) begin
    buff_eop    <=  1;
  end else if (tx_usr_axis_tvalid & tx_usr_axis_tready) begin
    buff_eop    <=  0;
  end
end

endmodule

buff_eop as markdebug

truth table

\$\endgroup\$
16
  • \$\begingroup\$ I'm having trouble replicating this. My attempt to synthesize this code, with all signals directly broken out to IOBs, gives me a single FDSE ("D Flip-Flop with Clock Enable and Synchronous Set") that gets cleared to 0 by tvalid && tready and set to 1 (with higher priority) by rst || (tvalid && tlast && tready). I'm using Vivado 2019.1 targeting an xc7a12. \$\endgroup\$
    – nanofarad
    Commented Mar 21, 2021 at 0:30
  • \$\begingroup\$ (to add to above, the synthesized schematic I get is i.sstatic.net/vzkYt.png) \$\endgroup\$
    – nanofarad
    Commented Mar 21, 2021 at 0:36
  • \$\begingroup\$ Interesting! I'm using Vivado 2020.1. I find the same result as you if I isolate and export the signals as ports. Nevertheless by keeping buff_eop as internal with mark_debug="true", I get the FDRE with the LUT feedback. I edited my question with the result. \$\endgroup\$
    – None
    Commented Mar 21, 2021 at 0:51
  • 1
    \$\begingroup\$ Reg: Any registers have to be reset to 0 and nothing else, this should be a developer rule: No. It is never the case. "developer" (Read "designer") decides the reset value. \$\endgroup\$
    – maximus
    Commented Mar 21, 2021 at 22:09
  • 1
    \$\begingroup\$ The reset was released much before the clock starts, therefore the register never goes to the reset value. (MMCM locks faster than GTY's common) Wrong reset for the clock. What I need to investigate is why it works on a different project using the same clock/reset topology. Anyway, thank you all! \$\endgroup\$
    – None
    Commented Mar 22, 2021 at 7:41

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.