Tuesday, October 27, 2009

Don't optimize my LUT please!

Sometimes you manually instantiate a LUT primitive (e.g. LUT6_2) to add routing delays to the signal path or precisely control the routing resources used but only to find out that the tool either optimizes it out or swaps pins. This can be prevented by using the LOCK_PINS and SAVE NET FLAG (S) constraints (Xilinx Constrants Guide). Below are the code snippets for Verilog and VHDL that work in ISE 11.3:

Verilog Example (download luts_vlog.v):
(* S="TRUE" *) reg [5:0]  lut_in_r;

LUT6_2 #(
    .INIT (64'h0000_0000_0000_0001)
) LUT_U0 (
    .I0 (lut_in_r[0]),
    .I1 (lut_in_r[1]),
    .I2 (lut_in_r[2]),
    .I3 (lut_in_r[3]),
    .I4 (lut_in_r[4]),
    .I5 (1'b1       ),
    .O5 (lut_out5_d ),
    .O6 (lut_out6_d )         

VHDL Example (download luts_vhd.vhd):
attribute LOCK_PINS : string;
attribute BEL       : string;
attribute S         : string;
attribute BEL       of LUT_U0   : label  is "A6LUT";
attribute LOCK_PINS of LUT_U0   : label  is "ALL";
attribute         of lut_in_r : signal is "TRUE";

LUT_U0: LUT6_2
    generic map (
        INIT => X"0000000000000001"
    port map (
        I0 => lut_in_r(0),
        I1 => lut_in_r(1),
        I2 => lut_in_r(2),
        I3 => lut_in_r(3),
        I4 => lut_in_r(4),
        I5 => '1',
        O5 => lut_out5_d,
        O6 => lut_out6_d         

After synthesis, you should see messages like below showing that XST picked up the design constraints:
Set user-defined property "S = TRUE" for signal .
Set user-defined property "BEL =  A6LUT" for instance  in unit .
Set user-defined property "LOCK_PINS =  ALL" for instance  in unit .
After the implementation is done, open the design in FPGA_EDITOR and check that the placement of the LUT and the pin order match the source code. Below is a snapshot of what it looks like for the example above:


  1. Hi Jim,

    I have almost the same problem. I am implementing a non-conventional circuit as follows (I am measuring LUT internal delays for different inputs..some I need this to work):

    I am instantiating an LUT that implements a buffer Out=A1. The function of the LUT is not dependent on other LUT inputs. In other words,the rest of the inputs are don't cares, but I would like to keep them in my design. Here is my module:


    module control(A1,Out, T);

    input A1, T;

    output Out;

    LUT6 #(
    .INIT(64'haaaaaaaaaaaaaaaa) // This implement a buffer hex a=binary 1010
    ) LUT6_inst (
    .O(Out), // LUT general output
    .I0(A1), // LUT input
    .I1(T), // LUT input
    .I2(T), // LUT input
    .I3(T), // LUT input
    .I4(T), // LUT input
    .I5(T) // LUT input



    The rest of the inputs are being connected to each other (net "t") and controlled by another logic gate.

    In my UCF file, I specify the following location constaint:

    INST "LUT6_inst" LOC = "SLICE_X17Y27";

    Now when the design is synthesize, I see the LUT in the RTL/Technology schematic the way I want...but what comes after MAP and PAR does not include the "T" net, which is apparently optimized out. In other word, the physical design view on FPGA editor is the LUT with only one input (A1), and there is no sign of the net "T".

    More weired is that in the MAP report there is nothing any nets being removed...!

    I searched a little bit and added the following MAP/Synthesis constaints but the problems still persists:


    module control(A1,Out, T);

    (* KEEP = "TRUE" *) (* S = "TRUE" *) input A1, T;

    (* KEEP = "TRUE" *) (* S = "TRUE" *) output Out;

    (* LOCK_PINS = "all" *) LUT6 #(

    .INIT(64'haaaaaaaaaaaaaaaa) // Specify LUT Contents
    ) LUT6_inst (
    .O(Out), // LUT general output
    .I0(A1), // LUT input
    .I1(T), // LUT input
    .I2(T), // LUT input
    .I3(T), // LUT input
    .I4(T), // LUT input
    .I5(T) // LUT input



    I also tried adding the following to the UCF file instead of the verilog source to no avail.

    NET "T" KEEP;

    NET "T" S;

    I get the following message:

    WARNING:Par:288 - The signal T_IBUF has no load. PAR will not attempt to route this signal.

    and when i look in FPGA editot there is the LUT with only one input being used!

    BTW, I am using Xilinx ISE Pack 11.4.

    I would really appreciate your help!



  2. Why do you want to keep the inputs that are not used in LUT equation?

  3. Hi All,

    this is great mini-howto but you should add a BIG-FAT-NOTE that 'map -global_opt ...' will optimize away all this lock/save magic ;)

    i've checked with planahead a simple scenario:

    data_i(pad) -> open-latch -> open-latch -> data_o(pad)

    latches are always open: locked LUT1 (I0=gnd,INIT=X"1") drives gates.

    such model survives standard mapper's optimizations (which normally optimizes open latches away) but global mapper's optimizations trims locked lut, latches and simply routes from data ibuf to obuf.